如何使用 AWS SES 在电子邮件中发送附件


how to send attachments in emails using AWS SES

我正在尝试使用此处的代码使用亚马逊的SES库以编程方式发送电子邮件。调整后,我有以下代码段。

SESUtils.php

<?php
require_once('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
 *
 * Update: Error checking and new params input array provided by Michael Deal
 */
class SESUtils {
const version = "1.0";
const AWS_KEY = SES_KEY;
const AWS_SEC = SES_SECRET;
const AWS_REGION = "us-east-1";
const MAX_ATTACHMENT_NAME_LEN = 60;
/**
 * Usage:
    $params = array(
      "to" => "email1@gmail.com",
      "subject" => "Some subject",
      "message" => "<strong>Some email body</strong>",
      "from" => "sender@verifiedbyaws",
      //OPTIONAL
      "replyTo" => "reply_to@gmail.com",
      //OPTIONAL
      "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
 * 
 * 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/alternative;'n";
    $boundary = uniqid("_Part_".time(), true); //random unique string
    $msg .= " boundary='"$boundary'"'n";
    $msg .= "'n";
    // now the actual message
    $msg .= "--$boundary'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);
    $msg .= "'n";
    // now, the html text
    $msg .= "--$boundary'n";
    $msg .= "Content-Type: text/html; charset=utf-8'n";
    $msg .= "Content-Transfer-Encoding: 7bit'n";
    $msg .= "'n";
    $msg .= $body;
    $msg .= "'n";
    // add attachments
    if (is_array($files)) {
        $count = count($files);
        foreach ($files as $idx => $file) {
            if ($idx !== 0)
                $msg .= "'n";
            $msg .= "--$boundary'n";
            $msg .= "Content-Transfer-Encoding: base64'n";
            $clean_filename = mb_substr($file["name"], 0, 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']));
            if (($idx + 1) === $count)
                $msg .= "=='n";
            $msg .= "--$boundary";
        }
        // close email
        $msg .= "--'n";
    }
    // now send the email out
    try {
        file_put_contents("log.txt", $msg);
        $ses_result = $client->sendRawEmail(
                array(
            '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;
    }
}
}
class ResultHelper {
    public $success = true;
    public $result_text = "";
    public $message_id = "";
}
?>

以及我用来发送实际电子邮件的功能

function sendAttachmentEmail($from, $to, $subject, $message, $attachmentPaths=array()){
    client = SesClient::factor(array('key' => SES_KEY, 'secret' => SES_SECRET, 'region' => 'us-east-1'));
    $attachments = array();
    foreach($attachmentPaths as $path){
        $fileName = explode("/",, $path);
        $fileName = $fileName[count($fileName)-1];
        $extension = explode(".", $fileName);
        $extension = strtoupper($extension[count($extension)-1]);
        $mimeType = "";
        if($extension == 'PDF') $mimeType = 'application/pdf';
        elseif($extension == 'CSV') $mimeType = 'test/csv';
        elseif($extension == 'XLS') $mimeType = 'application/vnd.ms-excel';
        array_push($attachments, array("name" => $fileName, "filepath" => $path, "mime" => $mimeType));
    }
    $params = array(
        "from" => $from,
        "to" => $to,
        "subject" => $subject,
        "message" => $message,
        "replyTo" => $from,
        "files" => $attachments
    );
    $res = SESUtils::sendMail($params);
    return $res;
}
sendAttachmentEmail("jesse@aol.com", "jesse@aol.com", 'test', 'test', array("/path/to/file.pdf"));

当我运行它时,返回的消息是一个错误,说"Expected ';', got "Reports" - To: jesse@aol.com, Sender: jesse@aol.com, Subject: test".有人知道我可能错过了什么吗?发送的消息的内容是

To: jesse@aol.com
From: jesse@aol.com
Reply-To: jesse@aol.com
Subject: test
MIME-Version: 1.0
Content-Type: multipart/alternative;
 boundary="_Part_142255491754ca7725b0bf89.40746157"
--_Part_142255491754ca7725b0bf89.40746157
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: 7bit
test
--_Part_142255491754ca7725b0bf89.40746157
Content-Type: text/html; charset=utf-8
Content-Transfer-Encoding: 7bit
test
--_Part_142255491754ca7725b0bf89.40746157
Content-Transfer-Encoding: base64
Content-Type: application/pdf; name=file.pdf;
Content-Disposition: attachment; filename=file.pdf;

晚了,但我希望这可以帮助其他人。

实现这一目标的最佳方法是使用 PHPMailer 撰写电子邮件,并让 MIMEMessage 将其作为 RawMessage 传递给 AWS SES 客户端

<小时 />

与作曲家一起安装:

$ composer require phpmailer/phpmailer
<小时 />

PHPMailer 朴素的例子:

// Create PHPMailer instance
$mail = new 'PHPMailer'PHPMailer'PHPMailer;
// Set the email values
$mail->setFrom("foo@bar.com", "Jhon Doe");
$mail->addAddress("destination@somedomain.com");
$mail->Subject = "Hi There ! ";
$mail->Body = <<<EOS
Your email content, <br>
you can write it even as a <strong>HTML document</strong>
EOS;
$mail->AltBody = <<<EOS
Your email content, here you write plain text body for clients that do not support html.
EOS;
// Here you attach your file or files
// @string path
// @string file_name. If not specified, it takes the original name from the path.
$mail->addAttachment("/path/to/file.xlsx", 'my_file.xlsx');
// Here is the magic
$mail->preSend();
$rawMessage = $mail->getSentMIMEMessage();
<小时 />

现在,您可以将MIMEMessage传递给SES SDK中的sendRawEmail方法。

$credentials = new Aws'Credentials'Credentials('XXXXX', 'YYYYYYYYYYY');
$ses_client = new Aws'Ses'SesClient([
        'credentials' => $credentials,
        'version' => '2010-12-01',
        'region'  => 'us-west-2'
]);

$ses_client->sendRawEmail([
            "RawMessage" => [
                "Data" => $rawMessage
            ]
]);

就是这样!

这是我使用 AWS PHP SDK V3.x 的 PHP 7 工作解决方案。此解决方案将发送带有一个附件的 HTML 邮件:

use Aws'Ses'SesClient;
$gAWS_SES_client = SesClient::factory(array(
    'version'=> 'latest',
    'region' => 'eu-west-1',
    'credentials' => array(
        'key' => 'my_secret_key',
        'secret'  => 'my_secret_pw'
  ) 
));

function sendRAWEmailViaSES($myArrayToAdresses, $myFromAdress, $mySubject, $myHTMLBody, $myFilePath){
    global $gAWS_SES_client;
    echo "'n<BR>Now in sendRAWEmailViaSES()<BR>'n";
    $myStringToAddresses = implode(",", $myArrayToAdresses);
    $myFileName = basename($myFilePath);;
    $myDataAttachedFile = file_get_contents($myFilePath);
    $myDataAttachedFile = chunk_split(base64_encode($myDataAttachedFile));  
    $myFileMimeInfo = finfo_open(FILEINFO_MIME_TYPE);
    $myFileMimeType = finfo_file($myFileMimeInfo, $myFilePath);     
    $mySeparator = md5(time());
    $mySeparator_multipart = md5($mySubject . time());      
    $myMessage = "";
    $myMessage .= "MIME-Version: 1.0'n";
    $myMessage .= "To: ".$myStringToAddresses."'n"; 
    $myMessage .= "From:".$myFromAdress."'n";   
    $myMessage .= "Subject:".$mySubject."'n";
    $myMessage .= "Content-Type: multipart/mixed; boundary='"".$mySeparator_multipart."'"'n";
    $myMessage .= "'n--".$mySeparator_multipart."'n";
    $myMessage .= "Content-Type: multipart/alternative; boundary='"".$mySeparator."'"'n";
    $myMessage .= "'n--".$mySeparator."'n";
    $myMessage .= "Content-Type: text/html; charset='"UTF-8'"'n";
    $myMessage .= "'n".$myHTMLBody."'n";
    $myMessage .= "'n--".$mySeparator."--'n";
    $myMessage .= "--".$mySeparator_multipart."'n";
    $myMessage .= "Content-Type: ".$myFileMimeType."; name='"".$myFileName."'"'n";
    $myMessage .= "Content-Disposition: attachment; filename='"".$myFileName."'"'n";
    $myMessage .= "Content-Transfer-Encoding: base64'n'n";
    $myMessage .= $myDataAttachedFile."'n";
    $myMessage .= "--".$mySeparator_multipart."--";
    //echo "'n<BR>Message:<BR>'n";
    //print_r($myMessage);
    //echo "<BR>'n";        

    $myArraySES = [
        'Source'       => $myFromAdress,
        'Destinations' => $myArrayToAdresses,
        'RawMessage'   => [
            'Data' => $myMessage
        ]
    ];  
    echo "'n<HR>Trying to send mail via AAWS SES <BR>'n";

    try{
        $myResult = true;
        $myAPIResult = $gAWS_SES_client->sendRawEmail($myArraySES);
        //save the MessageId which can be used to track the request
        //$myMessageArrayID = $myAPIResult->get('MessageId');
        //echo("MessageId: $msg_id");
        //view sample output
        echo "'n<BR>SES Result:<BR>'n";
        print_r($myAPIResult);
        echo "<BR>'n";
    } catch (Exception $myObjError) {
        //An error happened and the email did not get sent
        $myErrorInfo = $myObjError->getMessage();
        echo "'n<BR>*** SES ERROR:<BR>'n";
        print_r($myErrorInfo);
        echo "<BR>'n";      
        $myfile = fopen("ses_send_error.txt", "w");
        fwrite($myfile, $myErrorInfo);
        fclose($myfile);
    }   

}