Monday, June 24, 2013

How to use Amazon SES to Send Email from PHP

Sending mail using Amazon's SES (Simple Email Service)

I couldn't find too many good examples for this online and the Amazon AWS PHP SDK had incomplete documentation for a SendEmail function when I was researching this topic.

NOTE: One pitfall with this is using the SMTP username and password instead of your AWS credentials.  Use your AWS credentials when sending emails using the SDK.

Otherwise, you may get this error:
SignatureDoesNotMatch, Status Code: 403, AWS Request ID: xxxxx, AWS Error Type: client, AWS Error Message: The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details. The Canonical String for this request should have been



It's easy to install the Amazon SDK using PEAR (per Amazon documentation): 
sudo pear -D auto_discover=1 install

  1. Install the SDK
  2. Know if your account is sandboxed or not - If you account is sandboxed, you will only be able to send emails to the email addresses in the verified senders list.
  3. Make sure your source email's sending address is listed as a verified sender - Verify an email address that you own and use that in your sample code.  Check this email and the ReturnPath address in your AWS console if you are getting the "Email address is not verified" error.
  4. If you use the ReturnPath parameter (not shown here) to receive bounced emails, then that email address or domain must be verified as well

When you have the right credentials, sending Email using the SDK is very easy.


Sample Code:

require 'AWSSDKforPHP/aws.phar';

use Aws\Ses\SesClient;
$client = SesClient::factory(array(
    'key'    => 'aws_key',
    'secret' => 'aws_secret',
    'region' => 'us-east-1'

//Now that you have the client ready, you can build the message

$msg = array();
$msg['Source'] = "";

//ToAddresses must be an array
$msg['Destination']['ToAddresses'][] = "";

$msg['Message']['Subject']['Data'] = "Text only subject";
$msg['Message']['Subject']['Charset'] = "UTF-8";

$msg['Message']['Body']['Text']['Data'] ="Text data of email";
$msg['Message']['Body']['Text']['Charset'] = "UTF-8";
$msg['Message']['Body']['Html']['Data'] ="HTML Data of email<br />";
$msg['Message']['Body']['Html']['Charset'] = "UTF-8";

     $result = $client->sendEmail($msg);

     //save the MessageId which can be used to track the request
     $msg_id = $result->get('MessageId');
     echo("MessageId: $msg_id");

     //view sample output
} catch (Exception $e) {
     //An error happened and the email did not get sent

//view the original message passed to the SDK 



Run the above code using the correct information and your emails should be on their way.  Make sure to set the SenderID, DKIM, and SPF on your domain and Amazon properly to prevent your emails getting marked as spam.


Because of a request from Mohit Singh, I've updated the code to allow for adding a single attachment to the email.  See below for the details.

Using Attachments:

Use this example code in your program to send an email with an attachment using Amazon SES.


$subject_str = "Some Subject";
$body_str = "<strong>Some email body</strong>";
$attachment_str = get_file_contents("/htdocs/test/sample.pdf");

//send the email
$result = SESUtils::deliver_mail_with_attachment(

    array('', ''),       
    $subject_str, $body_str, 'sender@verifiedbyaws', 

//now handle the result if you wish

Complete Source for PHP Solution for sending mail using SES

Update #2 - (2015-01-27) Michael Deal was kind enough to provide additional features and enhancements in this new version

Update #3 - (2015-03-03) Code has been updated to properly handle plaintext with HTML and multiple attachments.  It's not handled quite the way you would think.  Thank you RFC-2046!



use Aws\Ses\SesClient;

 * SESUtils is a tool to make it easier to work with Amazon Simple Email Service
 * Features:
 * A client to prepare emails for use with sending attachments or not
 * There is no warranty - use this code at your own risk.  
 * @author sbossen 
 * Update: Error checking and new params input array provided by Michael Deal
 * Update2: Corrected for allowing to send multiple attachments and plain text/html body
 *   Ref: Http://
class SESUtils {

    const version = "1.0";
    const AWS_KEY = "YOUR-KEY";
    const AWS_SEC = "YOUR-SECRET";
    const AWS_REGION = "us-east-1";

     * Usage:
        $params = array(
          "to" => "",
          "subject" => "Some subject",
          "message" => "<strong>Some email body</strong>",
          "from" => "sender@verifiedbyaws",
          "replyTo" => "",
          "files" => array(
            1 => array(
               "name" => "filename1", 
              "filepath" => "/path/to/file1.txt", 
              "mime" => "application/octet-stream"
            2 => array(
               "name" => "filename2", 
              "filepath" => "/path/to/file2.txt", 
              "mime" => "application/octet-stream"
      $res = SESUtils::sendMail($params);
     * NOTE: When sending a single file, omit the key (ie. the '1 =>') 
     * or use 0 => array(...) - otherwise the file will come out garbled
     * ie. use:
     *    "files" => array(
     *        0 => array( "name" => "filename", "filepath" => "path/to/file.txt",
     *        "mime" => "application/octet-stream")
     * For the 'to' parameter, you can send multiple recipiants with an array
     *    "to" => array("", "")
     * use $res->success to check if it was successful
     * use $res->message_id to check later with Amazon for further processing
     * use $res->result_text to look for error text if the task was not successful
     * @param array $params - array of parameters for the email
     * @return \ResultHelper
    public static function sendMail($params) {

        $to = self::getParam($params, 'to', true);
        $subject = self::getParam($params, 'subject', true);
        $body = self::getParam($params, 'message', true);
        $from = self::getParam($params, 'from', true);
        $replyTo = self::getParam($params, 'replyTo');
        $files = self::getParam($params, 'files');

        $res = new ResultHelper();

        // get the client ready
        $client = SesClient::factory(array(
                    'key' => self::AWS_KEY,
                    'secret' => self::AWS_SEC,
                    'region' => self::AWS_REGION

        // build the message
        if (is_array($to)) {
            $to_str = rtrim(implode(',', $to), ',');
        } else {
            $to_str = $to;

        $msg = "To: $to_str\n";
        $msg .= "From: $from\n";

        if ($replyTo) {
            $msg .= "Reply-To: $replyTo\n";

        // in case you have funny characters in the subject
        $subject = mb_encode_mimeheader($subject, 'UTF-8');
        $msg .= "Subject: $subject\n";
        $msg .= "MIME-Version: 1.0\n";
        $msg .= "Content-Type: multipart/mixed;\n";
        $boundary = uniqid("_Part_".time(), true); //random unique string
        $boundary2 = uniqid("_Part2_".time(), true); //random unique string
        $msg .= " boundary=\"$boundary\"\n";
        $msg .= "\n";

        // now the actual body
        $msg .= "--$boundary\n";

        //since we are sending text and html emails with multiple attachments
        //we must use a combination of mixed and alternative boundaries
        //hence the use of boundary and boundary2
        $msg .= "Content-Type: multipart/alternative;\n";
        $msg .= " boundary=\"$boundary2\"\n";
        $msg .= "\n";
        $msg .= "--$boundary2\n";

        // first, the plain text
        $msg .= "Content-Type: text/plain; charset=utf-8\n";
        $msg .= "Content-Transfer-Encoding: 7bit\n";
        $msg .= "\n";
        $msg .= strip_tags($body); //remove any HTML tags
        $msg .= "\n";

        // now, the html text
        $msg .= "--$boundary2\n";
        $msg .= "Content-Type: text/html; charset=utf-8\n";
        $msg .= "Content-Transfer-Encoding: 7bit\n";
        $msg .= "\n";
        $msg .= $body; 
        $msg .= "\n";
        $msg .= "--$boundary2--\n";

        // add attachments
        if (is_array($files)) {
            $count = count($files);
            foreach ($files as $file) {
                $msg .= "\n";
                $msg .= "--$boundary\n";
                $msg .= "Content-Transfer-Encoding: base64\n";
                $clean_filename = self::clean_filename($file["name"], self::MAX_ATTACHMENT_NAME_LEN);
                $msg .= "Content-Type: {$file['mime']}; name=$clean_filename;\n";
                $msg .= "Content-Disposition: attachment; filename=$clean_filename;\n";
                $msg .= "\n";
                $msg .= base64_encode(file_get_contents($file['filepath']));
                $msg .= "\n--$boundary";
            // close email
            $msg .= "--\n";

        // now send the email out
        try {
            $ses_result = $client->sendRawEmail(
                'RawMessage' => array(
                    'Data' => base64_encode($msg)
                    ), array(
                'Source' => $from,
                'Destinations' => $to_str
            if ($ses_result) {
                $res->message_id = $ses_result->get('MessageId');
            } else {
                $res->success = false;
                $res->result_text = "Amazon SES did not return a MessageId";
        } catch (Exception $e) {
            $res->success = false;
            $res->result_text = $e->getMessage().
                    " - To: $to_str, Sender: $from, Subject: $subject";
        return $res;

    private static function getParam($params, $param, $required = false) {
        $value = isset($params[$param]) ? $params[$param] : null;
        if ($required && empty($value)) {
            throw new Exception('"'.$param.'" parameter is required.');
        } else {
            return $value;

    Clean filename function - to be mail friendly 
    public static function clean_filename($str, $limit = 0, $replace=array(), $delimiter='-') {
        if( !empty($replace) ) {
            $str = str_replace((array)$replace, ' ', $str);

        $clean = iconv('UTF-8', 'ASCII//TRANSLIT', $str);
        $clean = preg_replace("/[^a-zA-Z0-9\.\/_| -]/", '', $clean);
        $clean = preg_replace("/[\/| -]+/", '-', $clean);
        if ($limit > 0) {
            //don't truncate file extension
            $arr = explode(".", $clean);
            $size = count($arr);
            $base = "";
            $ext = "";
            if ($size > 0) {
                for ($i = 0; $i < $size; $i++) {
                    if ($i < $size - 1) { //if it's not the last item, add to $bn
                        $base .= $arr[$i];
                        //if next one isn't last, add a dot
                        if ($i < $size - 2)
                            $base .= ".";
                    } else {
                        if ($i > 0)
                            $ext = ".";
                        $ext .= $arr[$i];
            $bn_size = mb_strlen($base);
            $ex_size = mb_strlen($ext);
            $bn_new = mb_substr($base, 0, $limit - $ex_size);
            // doing again in case extension is long
            $clean = mb_substr($bn_new.$ext, 0, $limit); 
        return $clean;

class ResultHelper {

    public $success = true;
    public $result_text = "";
    public $message_id = "";



Sending multiple attachments using SES - Completed!

The above is a more complete and robust version of the sending email attachments with Amazon SES.  The one above now lets you have more than one attachment to send from the previous version.  Hope you enjoyed this and thanks to all for participating! 


  1. You are my hero. Thank you so much for this post!

    1. You're welcome! Glad I could help. If you wouldn't mind adding a +1, I'd appreciate it.

  2. This comment has been removed by a blog administrator.

  3. Despite the fact that there are a huge number of retail sites on the web, a couple of significant brands keep on overwhelming, much like customary high road retail. By some separation, Amazon is the biggest online retailer of all.Buy Niche Organic 100% Safe USA based Amazon Traffic

    1. Great Article
      Cloud Computing Projects

      Networking Projects

      Final Year Projects for CSE

      JavaScript Training in Chennai

      JavaScript Training in Chennai

      The Angular Training covers a wide range of topics including Components, Angular Directives, Angular Services, Pipes, security fundamentals, Routing, and Angular programmability. The new Angular TRaining will lay the foundation you need to specialise in Single Page Application developer. Angular Training

  4. , you can procure a specialist PHP web designer so as to tweak your site according to your business prerequisites, which is very financially savvy. CakePHP Application Development

  5. PHP's essential use is as an "implanted" scripting language, which implies that the real PHP code is inserted in HTML code.Why use Laravel

  6. Find approved Motorola administration focuses close to you in . Discover Location. It would be ideal if you enter your city to view Service Centers that are approved to fix your gadget.
    Best mobile service centre.

  7. You have a good point here!I totally agree with what you have said!!Thanks for sharing your views...hope more people will read this article!!!
    tree service near me in tequesta

  8. Superbly written article, if only all bloggers offered the same content as you, the internet would be a far better place.
    bathroom remodel reno nv

  9. Thanks for a wonderful share. Your article has proved your hard work and experience you have got in this field. Brilliant .i love it reading.
    septic tank cleaning west palm beach

  10. I have read your article, it is very informative and helpful for me.I admire the valuable information you offer in your articles. Thanks for posting it..
    durham remodeling contractors

  11. Hello, I have browsed most of your posts. This post is probably where I got the most useful information for my research. Thanks for posting, maybe we can see more on this. Are you aware of any other websites on this subject.
    ac installation royal palm beach

  12. Great article and a nice way to promote online. I’m satisfied with the information that you provided
    bathroom remodelers raleigh

  13. This post is good enough to make somebody understand this amazing thing, and I’m sure everyone will appreciate commercial ac unit west palm beach

  14. You have a good point here!I totally agree with what you have said!!Thanks for sharing your views...hope more people will read this article!!!
    commercial screen enclosures cape coral

  15. Very nice bro, thanks for sharing this with us. Keep up the good work and Thank you for sharing information tree trimmers port st lucie

  16. Great blog and a great topic as well I really get amazed to read this. It’s really good.
    free airdrops

  17. This comment has been removed by a blog administrator.

  18. Great blog thanks for sharing Instagram and Facebook have provided an amazing place for new brands to grow and flourish. We can find the perfect niche for your brand on the best social media platforms. Marketing through social media brings forth global audience without all these physical boundaries. Analyze and take over the competition with ease with Adhuntt Media’s digital marketing tools and strategies.
    digital marketing company in chennai

  19. Nice blog thanks for sharing You have come to the right place. Karuna Nursery Gardens is the ideal place to begin your journey into landscape gardening. Our specialists have built some of the finest landscape garden in Chennai that too at the best price and amazing service.
    plant nursery in chennai

  20. Excellent blog thanks for sharing Pixies beauty Shop is the best place to buy cosmetics in Chennai. With thousands of premium imported brands to choose from, you’ll never run out of lipstick again. And don’t forget about the best offers and value they provide.
    beauty Shop in Chennai

  21. כתיבה מעולה, אהבתי. אשתף עם העוקבים שלי.
    קבוצת גבאי פייסבוק

  22. This comment has been removed by the author.

  23. הדעות שלי קצת חלוקות בעניין הזה אבל ללא ספק כתבת מעניין מאוד.
    טבעות אירוסין זהב לבן

  24. רציתי רק לשאול, אפשר לשתף את הפוסט בבלוג שלי
    רהיטים לסלון

  25. לגמרי פוסט שדורש שיתוף תודה.
    פינות אוכל

  26. מזל שנתקלתי בכתבה הזאת. בדיוק בזמן
    טיפול prp לשיער

  27. אין ספק שזה אחד הנושאים המעניינים. תודה על השיתוף.
    אירוע בת מצווה

  28. לגמרי פוסט שדורש שיתוף תודה.
    מארז ליולדת

  29. תודה על השיתוף. מחכה לכתבות חדשות.

  30. Great Information,it has lot for stuff which is informative.I will share the post with my friend.
    animal jewelry

  31. The best way to spend your night in 31 Dec with Hong Kong Escorts Girls, call us for bookings

  32. סופסוף מישהו שתואם לדעותיי בנושא. תודה.
    בלוק תמונה

  33. אין ספק שזה אחד הנושאים המעניינים. תודה על השיתוף.
    התקנת אינטרקום

  34. Thanks for sharing this nice informatione!
    financial modelling to give you confidence in your financial strategy and provide business valuations.

  35. It’s difficult to find experienced people in this particular topic, however, you seem like you know what you’re talking about! Thanks
    Tech news

  36. Very useful blog thanks for sharing IndPac India the German technology Packaging and sealing machines in India is the leading manufacturer and exporter of Packing Machines in India.

  37. Awesome article, it was exceptionally helpful! I simply began in this and I'm becoming more acquainted with it better. The post is written in very a good manner and it contains many useful information for me. Thank you very much and will look for more postings from you.

    digital marketing blog
    digital marketing bloggers
    digital marketing blogs
    digital marketing blogs in india
    digital marketing blog 2020
    digital marketing blog sites
    skartec's digital marketing blog
    skartec's blog
    digital marketing course
    digital marketing course in chennai
    digital marketing training
    skartec digital marketing academy

  38. Thanks for your sharing! The information your share is very useful to me and many people are looking for them just like me!

    We have collection of best 2020 sex doll to fulfill your desire, so if you need realistic female sex dolls then Love Doll Palace is largest online store for you , who are providing young love doll for you, these are made by silicone and TPE, which will give you full happiness at sex duration and you can enjoy with her at any position.

  39. אין ספק שהפוסט הזה דורש שיתוף. תודה
    ניהול מוניטין בגוגל

  40. סופסוף מישהו שתואם לדעותיי בנושא. תודה.
    השקעות מניבות

  41. כתיבה מעולה, אהבתי. אשתף עם העוקבים שלי.
    עיצוב חווית משתמש

  42. Awesome and interesting article. Great things you've always shared with us. Visit Kidoriman and see Kidoriman reviews show that how people are happy with our extensive services. Our high-quality products and clothes make our customer happy. As a result, they prefer us for the shopping every time.

  43. Application programs are intended to do explicit errands to be executed through the PC and the working framework programs are utilized to deal with the inward elements of the PC to encourage utilization of use program.
    itools crack reddit

  44. i am browsing this website dailly , and get nice facts from here all the time .

  45. פוסט מרענן במיוחד. לגמרי משתף.

  46. A backlink is a link created when one website links to another. Backlinks are important to SEO & impact for higher ranking. In my 7+ years seo Career i see, without backlinks a website doesn't rank higher on google SERP.

    Get Your 300+ High Quality DoFollow Backlinks Here!

    Order Now with Full Confidence & 100% satisfaction.

  47. With Brandsoo, it’s never been easier or more convenient to shop high quality domain names and professional business name ideas logos that’ll instantly give your brand a leg up and resonate with your audience! With many different domain sellers all competing for your business, you need to know where your business and brand will see.

  48. I really appreciate this wonderful post that you have provided for us.
    Garage door repair Pickering

  49. With massive progress in educational technology schools are becoming hot for teachers better equipped than ever before. It’s a great time to consider a new job in education.

  50. Forex Signals, MT4 and MT5 Indicators, Strategies, Expert Advisors, Forex News, Technical Analysis and Trade Updates in the FOREX IN WORLD

    Forex Signals Forex Strategies Forex Indicators Forex News Forex World

  51. Thats great. I got the right one information at the right time for the right situation. Thanks for sharing.

    Global Asset Management Korea

  52. Thanks for one marvelous posting! I enjoyed reading it; you are a great author. I will make sure to bookmark your blog and may come back someday. I want to encourage that you continue your great posts.
    oracle training in chennai

    oracle training institute in chennai

    oracle training in bangalore

    oracle training in hyderabad

    oracle training

    oracle online training

    hadoop training in chennai

    hadoop training in bangalore

  53. I recently came across your article and have been reading along. I want to express my admiration of your writing skill and ability to make readers read from the beginning to the end. I would like to read newer posts and to share my thoughts with you.Your post is just outstanding! thanks for such a post,its really going great and great work.You have provided great knowledge
    Azure Training in Chennai

    Azure Training in Bangalore

    Azure Training in Hyderabad

    Azure Training in Pune

    Azure Training | microsoft azure certification | Azure Online Training Course

    Azure Online Training

  54. Excellent Blog! I would Thanks for sharing this wonderful content.its very useful to us.This is incredible,I feel really happy to have seen your webpage.I gained many unknown information, the way you have clearly explained is really fantastic.keep posting such useful information.
    Full Stack Training in Chennai | Certification | Online Training Course
    Full Stack Training in Bangalore | Certification | Online Training Course

    Full Stack Training in Hyderabad | Certification | Online Training Course
    Full Stack Developer Training in Chennai | Mean Stack Developer Training in Chennai
    Full Stack Training

    Full Stack Online Training

  55. This was an extremely wonderful post. Thanks for providing this info. 13 Reasons Why Hoodie

  56. Shield Security Solutions Provides Ontario Security Training, Security Guard License or Security License in Ontario. Get Started Today

  57. Great information about wilderness for beginners giving the opportunity for new people.
    rocketman denim jacket

  58. Email is performing a very important rule in the business community in their communication maintain. I appreciate your efforts to create this topic. dissertation proposal writing services

  59. Great blog, thanks for sharing with us. Ogen Infosystem is a leading web designing service provider in Delhi, India.
    Website Designing Company in India

  60. חייב להחמיא על הכתיבה. מאמר מצוין.

    בריכות שחיה פיברגלס

  61. I have to say this has been probably the most helpful posts for me. Please keep it up. I cant wait to read whats next.

    Garage Door Repair Okotoks

  62. This is really amazing, you are very skilled blogger. Visit Ogen Infosystem for professional website designing and SEO Services.
    SEO Service in Delhi

  63. it is really a great and helpful piece of info. I am glad that you shared this helpful information with us. Please keep us informed like this. Thank you for sharing.
    malaysia visa

  64. אם כי אני לא מסכים עם כל מה שנכתב, מאמר מעניין
    סובארו אימפרזה sti

  65. Our the purpose is to share the reviews about the latest Jackets,Coats and Vests also share the related Movies,Gaming, Casual,Faux Leather and Leather materials available Yellowstone Rip Wheeler Jacket

  66. I enjoyed over read your blog post. This was actually what i was looking for and i am glad to came here!
    Website: Antique jewellery designs

  67. Amazing Article,Really useful information to all So, I hope you will share more information to be check and share here.thanks for sharing .
    Website: Vietnam travel packages

  68. We are the Best Digital Marketing Agency in Chennai.Our team consists of very best of programmers,web developers,SEO experts and many others. we offer all digital marketing service at affordable cost.
    Thanks for the article…
    Best SEO analytics in chennai
    Website Designing Company in chennai
    Social Media marketing

  69. This is a wonderful article, Given so much info in it, Thanks for sharing. CodeGnan offers courses in new technologies and makes sure students understand the flow of work from each and every perspective in a Real-Time environment AR Course in Vijayawada. ,

  70. This is really too useful and have more ideas and keep sharing many techniques. Eagerly waiting for your new blog keep doing more.
    DevOps Training in Chennai
    DevOps Training in Bangalore
    DevOps Online Training
    DevOps Training in Coimbatore

  71. Thank you for this post, it help me, I will share it on facebook and buy facebook shares from this link

  72. Great blog! This is really helpful for my reference. Do share more such posts and keep us updated. Looking forward to more informative blogs from you.
    Cloud Computing Training in Chennai
    Cloud Computing Courses in Chennai
    Cloud Computing Courses in Bangalore
    Cloud Computing Courses in Coimbatore

  73. Nice Blog !
    Here We are Specialist in Manufacturing of Movies, Gaming, Casual, Faux Leather Jackets, Coats And Vests See Kayce Dutton Jacket

  74. Get instant assignment help service in Australia. We are in this service from last ten years and provide best assistance to all our clients. If you are in Australia and pursuing your graduation or post-graduation from over there, then you can get assistance from our experts. We believe in providing best to our clients to maintain a long relationship with our clients. You can expect from us a genuine work with zero plagiarism.

  75. Spot on with this article, I really think this website needs more attention. I'll probably be back to read more, thanks for the info.

  76. A thoughtful insight and fantastic suggestions you have on your website. You have obviously spent lots of time on this. Well done. Sons Of Anarchy Vest

  77. oooo that's great amazing information for this blog and lot of people share our opinions such a great plate foam. Yellowstone Blue Coat

  78. I’m excited to uncover this page. I need to to thank you for ones time for this particularly fantastic read!! I definitely really liked every part of it and i also have you saved to fav to look at new information in your site.
    Best Data Science Courses in Hyderabad

  79. Tally Solutions Pvt. Ltd., is an Indian multinational company that provides enterprise resource planning software. It is headquartered in Bengaluru, Karnataka India.
    tally training in chennai

    hadoop training in chennai

    sap training in chennai

    oracle training in chennai

    angular js training in chennai

  80. Great ....You have beautifully presented your thought in this blog post. I admire the time and effort you put into your blog and detailed information you offer.

    garage door repair east houston tx

  81. Very nice work, really appreciable. Good to know something new today, keep it up.
    1000 free youtube subscribers

  82. לא כל כך מסכים עם הכל כאן האמת.

    אינטרקום עם מצלמה

  83. I am glad to post a worthy article about the German Language Course and IELTS Coaching from KCR consultants, this may change your career growth and language skill.

  84. Good information and great post. I like the website, and am sure to keep returning.

    garage door repair southeast edmonton


  85. I have been working as a full-time academic at MyAssignmentHelpNow to help students with their academic writing requirements. We offered assignment help to the students who are struggling with their academic writing tasks. Our experts possess a good writing and researching skills and thus we are able to provide the best supervision to the students.

    Online Assignment Help

  86. The great website and information shared are also very appreciable. Usmle Step 1

  87. I was confused about this. thank you for this solutions.
    online classified ads platform