【问题标题】:Sending email with attachment using amazon SES使用亚马逊 SES 发送带附件的电子邮件
【发布时间】:2012-06-21 08:01:01
【问题描述】:

我正在尝试使用亚马逊 SES API 发送一封包含附件(pdf 文件)的电子邮件。

我正在使用 Symfony2,所以我在我的项目中包含了 AmazonWebServiceBundle。 我可以使用以下代码轻松发送一封简单的电子邮件(没有附件):

$ses = $this->container->get('aws_ses');
$recip = array("ToAddresses"=>array("Quilly@yourownpoet.com"));
$message = array("Subject.Data"=>"My Subject","Body.Text.Data"=>"My Mail body");
$result = $ses->send_email("Quilly@yourownpoet.com",$recip, $message);

不幸的是,要发送带有附件的电子邮件,我需要使用sendRawEmail 函数而不是 send_email 函数。

我无法找到如何使用此功能,有人可以帮忙吗?

【问题讨论】:

    标签: email symfony amazon-web-services


    【解决方案1】:

    是的,使用 SES 发送带有附件的电子邮件很痛苦。也许这会帮助仍在为此苦苦挣扎的其他人。我编写了一个简单的类来帮助简化对 sendRawEmail 的调用。

    用法:

    $subject_str = "Some Subject";
    $body_str = "<strong>Some email body</strong>";
    $attachment_str = file_get_contents("/htdocs/test/sample.pdf");
    
    //send the email
    $result = SESUtils::deliver_mail_with_attachment(
        array('email1@gmail.com', 'email2@lutz-engr.com'),       
        $subject_str, $body_str, 'sender@verifiedbyaws', 
        $attachment_str);
    
    //now handle the $result if you wish
    

    类:

    <?php
    require 'AWSSDKforPHP/aws.phar';
    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 
     * http://right-handed-monkey.blogspot.com
     */
    class SESUtils {
    
        const version = "1.0";
        const AWS_KEY = "your_aws_key";
        const AWS_SEC = "your_aws_secret";
        const AWS_REGION = "us-east-1";
        const BOUNCER = "bouncer@yourdomain.com";  //if used, this also needs to be a verified email
        const LINEBR = "\n";
        const MAX_ATTACHMENT_NAME_LEN = 60;
    
        /**
         * Usage
         * $result = SESUtils::deliver_mail_with_attachment(array('receipt@r.com', 'receipt2@b.com'), $subject_str, $body_str, 'validatedsender@aws', $attachment_str);
         * use $result->success to check if it was successful
         * use $result->message_id to check later with Amazon for further processing
         * use $result->result_text to look for error text if the task was not successful
         * 
         * @param type $to - individual address or array of email addresses
         * @param type $subject - UTF-8 text for the subject line
         * @param type $body - Text for the email
         * @param type $from - email address of the sender (Note: must be validated with AWS as a sender)
         * @return \ResultHelper
         */
        public static function deliver_mail_with_attachment($to, $subject, $body, $from, &$attachment = "", $attachment_name = "doc.pdf", $attachment_type = "Application/pdf", $is_file = false, $encoding = "base64", $file_arr = null) {
            $result = 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".self::LINEBR;
            $msg .="From: $from".self::LINEBR;
            //in case you have funny characters in the subject
            $subject = mb_encode_mimeheader($subject, 'UTF-8');
            $msg .="Subject: $subject".self::LINEBR;
            $msg .="MIME-Version: 1.0".self::LINEBR;
            $msg .="Content-Type: multipart/alternative;".self::LINEBR;
            $boundary = uniqid("_Part_".time(), true); //random unique string
            $msg .=" boundary=\"$boundary\"".self::LINEBR;
            $msg .=self::LINEBR;
            //now the actual message
            $msg .="--$boundary".self::LINEBR;
            //first, the plain text
            $msg .="Content-Type: text/plain; charset=utf-8".self::LINEBR;
            $msg .="Content-Transfer-Encoding: 7bit".self::LINEBR;
            $msg .=self::LINEBR;
            $msg .=strip_tags($body);
            $msg .=self::LINEBR;
            //now, the html text
            $msg .="--$boundary".self::LINEBR;
            $msg .="Content-Type: text/html; charset=utf-8".self::LINEBR;
            $msg .="Content-Transfer-Encoding: 7bit".self::LINEBR;
            $msg .=self::LINEBR;
            $msg .=$body;
            $msg .=self::LINEBR;
            //add attachments
            if (!empty($attachment)) {
                $msg .="--$boundary".self::LINEBR;
                $msg .="Content-Transfer-Encoding: base64".self::LINEBR;
                $clean_filename = mb_substr($attachment_name, 0, self::MAX_ATTACHMENT_NAME_LEN);
                $msg .="Content-Type: $attachment_type; name=$clean_filename;".self::LINEBR;
                $msg .="Content-Disposition: attachment; filename=$clean_filename;".self::LINEBR;
                $msg .=self::LINEBR;
                $msg .=base64_encode($attachment);
                //only put this mark on the last entry
                if (!empty($file_arr))
                    $msg .="==".self::LINEBR;
                $msg .="--$boundary";
            }
            if (!empty($file_arr) && is_array($file_arr)) {
                foreach ($file_arr as $file) {
                    $msg .="Content-Transfer-Encoding: base64".self::LINEBR;
                    $clean_filename = mb_substr($attachment_name, 0, self::MAX_ATTACHMENT_NAME_LEN);
                    $msg .="Content-Type: application/octet-stream; name=$clean_filename;".self::LINEBR;
                    $msg .="Content-Disposition: attachment; filename=$clean_filename;".self::LINEBR;
                    $msg .=self::LINEBR;
                    $msg .=base64_encode($attachment);
                    //only put this mark on the last entry
                    if (!empty($file_arr))
                        $msg .="==".self::LINEBR;
                    $msg .="--$boundary";
                }
            }
            //close email
            $msg .="--".self::LINEBR;
    
            //now send the email out
            try {
                $ses_result = $client->sendRawEmail(array(
                    'RawMessage' => array('Data' => base64_encode($msg))), array('Source' => $from, 'Destinations' => $to_str));
                if ($ses_result) {
                    $result->message_id = $ses_result->get('MessageId');
                } else {
                    $result->success = false;
                    $result->result_text = "Amazon SES did not return a MessageId";
                }
            } catch (Exception $e) {
                $result->success = false;
                $result->result_text = $e->getMessage()." - To: $to_str, Sender: $from, Subject: $subject";
            }
            return $result;
        }
    
    }
    
    
    class ResultHelper {
    
        public $success = true;
        public $result_text = "";
        public $message_id = "";
    
    }
    
    ?>
    

    我已经写了一篇博客文章来解决这个问题,也许它会对你或其他人有用:http://righthandedmonkey.com/2013/06/how-to-use-amazon-ses-to-send-email-php.html

    【讨论】:

    • 非常有用,谢谢。很惊讶 AWS PHP SDK 中没有这个功能。与其他 API 相比,SES 部分非常稀疏。
    • 您的使用代码中有错误。 PHP中的文件读取函数是file_get_contents,而不是get_file_contents。容易滑倒。除此之外,这个答案是根据我的情况剪切、粘贴、调整的。再次感谢。
    • 上面的代码对我不起作用,但它工作了 RightHandedMonkey 在这里提到的完整解决方案:righthandedmonkey.com/2013/06/…
    • 非常感谢 Righthandedmonkey 的解决方案!
    • 文件总是 1kb,数据崩溃。
    【解决方案2】:

    我设法以以下方式创建了一个原始 MIME 消息,以使用 Amazon SES sendRawEmail 发送带附件的电子邮件(.pdf 文件)。这是为了普通的 javascript 使用;当然也可以进一步完善它,添加其他内容类型。

    1. 使用 jsPDF 和 html2Canvas 之类的库来创建 PDF 文件并将内容保存到变量中并获取 base 64 数据:

      var pdfOutput = pdf.output();
      var myBase64Data = btoa(pdfOutput);
      
    2. 使用以下代码创建 MIME 消息。请注意,顺序很重要,否则电子邮件将最终成为暴露所有 base 64 数据的文本电子邮件:

      var fileName = "Attachment.pdf";
      var rawMailBody = "From: testmail@gmail.com\nTo: testmail@gmail.com\n";
      rawMailBody = rawMailBody + "Subject: Test Subject\n"; 
      rawMailBody = rawMailBody + "MIME-Version: 1.0\n"; 
      rawMailBody = rawMailBody + "Content-Type: multipart/mixed; boundary=\"NextPart\"\n\n"; 
      rawMailBody = rawMailBody + "--NextPart\n";  
      rawMailBody = rawMailBody + "Content-Type: application/octet-stream\n"; 
      rawMailBody = rawMailBody + "Content-Transfer-Encoding: base64\n"; 
      rawMailBody = rawMailBody + "Content-Disposition: attachment; filename=\"" + fileName + "\"\n\n"; 
      rawMailBody = rawMailBody + "Content-ID random2384928347923784letters\n"; 
      rawMailBody = rawMailBody + myBase64Data+"\n\n"; 
      rawMailBody = rawMailBody + "--NextPart\n";
      
    3. 调用 sendRawEmail:

       var params = {
            RawMessage: {
              Data: rawMailBody
            },
            Destinations: [],
            Source: 'testmail@gmail.com'
          };
      
       ses.sendRawEmail(params, function(err, data) {
         if (err) alert("Error: "+err); // an error occurred
         else     {
      
         alert("Success: "+data);           // successful response
         }
      
       }); 
      

    【讨论】:

      【解决方案3】:

      手动构建电子邮件,正如您明确表示的“太痛苦了”,维护自己的服务器只是为了发送电子邮件也是如此。这就是为什么我建议使用库来处理创建电子邮件的原因。

      例如,Swift mailer 有一个名为 Swift_Message 的类,可用于创建电子邮件和 include attachments

      以下示例直接取自documentation

      $message = (new Swift_Message())
        ->setSubject('Your subject')
        ->setFrom(['john@doe.com' => 'John Doe'])
        ->setTo(['receiver@domain.org', 'other@domain.org' => 'A name'])
        ->setBody('Here is the message itself')
        ->addPart('<q>Here is the message itself</q>', 'text/html')
        ->attach(Swift_Attachment::fromPath('my-document.pdf'))
      

      然后调用消息的toString方法,设置为RawMessage

      $result = $client->sendRawEmail([
          'RawMessage' => [
              'Data' => $message.toString()
          ]
      ]);      
      

      或者,您可以设置 symfony + swift mailer 以使用 SES SMTP 端点,请参阅symfony documentation 了解更多信息。

      【讨论】:

        【解决方案4】:

        经过多次尝试,我得出的结论是,直接从代码中向 Amazon SES 发送电子邮件太痛苦了。

        所以我没有更改代码中的任何内容,而是配置了我的 postfix 服务器。

        我遵循以下程序:http://docs.amazonwebservices.com/ses/latest/DeveloperGuide/SMTP.MTAs.Postfix.html 并使用 STARTTLS 配置集成。

        我不得不在 Amazon 控制台中请求 SMTP 凭证。

        现在一切正常,电子邮件已通过 Amazon SES 正确发送。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2015-06-15
          • 2013-05-25
          • 2015-08-24
          • 1970-01-01
          • 1970-01-01
          • 2018-04-01
          • 1970-01-01
          相关资源
          最近更新 更多