使用 Amazon SES API v2 傳送原始電子郵件 - Amazon Simple Email Service

本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。

使用 Amazon SES API v2 傳送原始電子郵件

您可以使用 Amazon SES API v2 SendEmail操作搭配指定的內容類型raw,使用原始電子郵件格式將自訂訊息傳送給收件人。

關於電子郵件標頭欄位

Simple Mail Transfer Protocol (SMTP) 會指定電子郵件訊息的傳送方式,方法是定義郵件信封及其部分參數,但它本身與訊息的內容無關。相反地,網際網路訊息格式 (RFC 5322) 會定義要如何建構訊息。

在網際網路訊息格式的明確定義下,每個電子郵件訊息都會含有標題和內文。標題包含訊息中繼資料,而內文則包含訊息本身。如需有關電子郵件標題和內文的詳細資訊,請參閱 Amazon SES 中的電子郵件格式

使用 MIME

SMTP 通訊協定最初設計用於傳送電子郵件訊息,其中僅包含 7 位元ASCII字元。此規格SMTP不足以進行非ASCII文字編碼 (例如 Unicode)、二進位內容或附件。多用途網際網路郵件延伸標準 (MIME) 的開發目的是使用 傳送許多其他類型的內容SMTP。

此MIME標準的運作方式是將訊息內文分成多個部分,然後指定要對每個部分執行的動作。例如,電子郵件訊息內文的一部分可能是純文字,而另一個部分可能是 HTML。此外, MIME 允許電子郵件訊息包含一或多個附件。訊息收件人可以在自己的電子郵件用戶端中檢視附件,也可以儲存附件。

訊息標題和內容則是以空白行分隔。每個部分的電子郵件則是以邊界為分隔,邊界為字元字串,用以標記出每個部分的開始與結束。

下列範例中的分段訊息包含文字和HTML部分,以及附件。附件應該放在附件標題的正下方,並且通常以 base64 編碼,如此範例所示。

From: "Sender Name" <sender@example.com> To: recipient@example.com Subject: Customer service contact info Content-Type: multipart/mixed; boundary="a3f166a86b56ff6c37755292d690675717ea3cd9de81228ec2b76ed4a15d6d1a" --a3f166a86b56ff6c37755292d690675717ea3cd9de81228ec2b76ed4a15d6d1a Content-Type: multipart/alternative; boundary="sub_a3f166a86b56ff6c37755292d690675717ea3cd9de81228ec2b76ed4a15d6d1a" --sub_a3f166a86b56ff6c37755292d690675717ea3cd9de81228ec2b76ed4a15d6d1a Content-Type: text/plain; charset=iso-8859-1 Content-Transfer-Encoding: quoted-printable Please see the attached file for a list of customers to contact. --sub_a3f166a86b56ff6c37755292d690675717ea3cd9de81228ec2b76ed4a15d6d1a Content-Type: text/html; charset=iso-8859-1 Content-Transfer-Encoding: quoted-printable <html> <head></head> <body> <h1>Hello!</h1> <p>Please see the attached file for a list of customers to contact.</p> </body> </html> --sub_a3f166a86b56ff6c37755292d690675717ea3cd9de81228ec2b76ed4a15d6d1a-- --a3f166a86b56ff6c37755292d690675717ea3cd9de81228ec2b76ed4a15d6d1a Content-Type: text/plain; name="customers.txt" Content-Description: customers.txt Content-Disposition: attachment;filename="customers.txt"; creation-date="Sat, 05 Aug 2017 19:35:36 GMT"; Content-Transfer-Encoding: base64 SUQsRmlyc3ROYW1lLExhc3ROYW1lLENvdW50cnkKMzQ4LEpvaG4sU3RpbGVzLENhbmFkYQo5MjM4 OSxKaWUsTGl1LENoaW5hCjczNCxTaGlybGV5LFJvZHJpZ3VleixVbml0ZWQgU3RhdGVzCjI4OTMs QW5heWEsSXllbmdhcixJbmRpYQ== --a3f166a86b56ff6c37755292d690675717ea3cd9de81228ec2b76ed4a15d6d1a--

訊息的內容類型為 multipart/mixed,這表示訊息有許多部分 (在這個範例中,分為內文與附件),而接收用戶端必須單獨處理每個部分。

內文部分中的內嵌是使用 multipart/alternative 內容類型的第二個部分。此內容類型表示每個部分都包含相同內容的替代版本 (在此情況下,包含文字版本和HTML版本)。如果收件人的電子郵件用戶端可以顯示HTML內容,則會顯示訊息內文的HTML版本。如果收件人的電子郵件用戶端無法顯示HTML內容,則會顯示訊息內文的純文字版本。

這兩種訊息版本也都包含附件 (在本案例中是包含部分客戶名稱的簡短文字檔案)。

當您將MIME部分巢狀在其他部分中時,如本範例所示,巢狀部分必須使用與父部分中的boundary參數不同的boundary參數。這些邊界應為獨特的字元字串。若要定義MIME部分之間的邊界,請輸入兩個連字號 (--),然後輸入邊界字串。在MIME部分結尾,將兩個連字號放在邊界字串的開頭和結尾。

注意

訊息不能有超過 500 個MIME部分。

MIME 編碼

為了維持與較舊系統的相容性,Amazon SES遵循 2RFC821 中SMTP定義的 7 位元ASCII限制。如果您想要傳送包含非ASCII字元的內容,您必須將這些字元編碼為使用 7 位元ASCII字元的格式。

電子郵件位址

電子郵件地址字串必須為 7 位元 ASCII。如果您要寄出的電子郵件地址或收件人的電子郵件地址網域部分包含 Unicode 字元,您必須使用 Punycode 編碼來將網域編碼。Punycode 不可用於電子郵件的本機部分 (也就是 @ 前的部分),也不能使用於「友善寄件人」名稱中。如果您想要在「易記」名稱中使用 Unicode 字元,則必須使用MIME編碼字語法來編碼「易記」名稱,如 中所述使用 Amazon SES API v2 傳送原始電子郵件。如需 Punycode 的詳細資訊,請參閱 RFC 3492

注意

此規則僅適用於您在訊息信封中指定的電子郵件地址,不適用於訊息標頭。當您使用 Amazon SES API v2 SendEmail操作時,您在 SourceDestinations 參數中指定的地址會分別定義信封寄件者和收件人。

電子郵件標頭

若要編碼訊息標頭,請使用MIME編碼字語法。MIME 編碼的單字語法使用下列格式:

=?charset?encoding?encoded-text?=

encoding 的值可以是 QB。如果編碼值為 Q,則值 encoded-text 必須使用 Q 編碼。如果編碼值為 B,則值 encoded-text 必須使用 base64 編碼。

例如,如果您想要在電子郵件主旨列中使用字串「Як ти поживаєш?」,您可以使用下列其中一種編碼:

  • Q 編碼

    =?utf-8?Q?=D0=AF=D0=BA_=D1=82=D0=B8_=D0=BF=D0=BE=D0=B6=D0=B8=D0=B2=D0=B0=D1=94=D1=88=3F?=
  • Base64 編碼

    =?utf-8?B?0K/QuiDRgtC4INC/0L7QttC40LLQsNGU0Yg/?=

如需 Q 編碼的詳細資訊,請參閱 RFC 2047。如需 base64 編碼的詳細資訊,請參閱 RFC 2045

訊息內文

若要編碼訊息的內文,您可以使用 quoted-printable 編碼或 base64 編碼。然後,使用 Content-Transfer-Encoding 標頭,指出您使用的編碼方案。

例如,假設您的訊息內文包含下列文字:

१९७२ मे रे टॉमलिंसन ने पहला ई-मेल संदेश भेजा | रे टॉमलिंसन ने ही सर्वप्रथम @ चिन्ह का चयन किया और इन्ही को ईमेल का आविष्कारक माना जाता है

如果您選擇使用 base64 編碼編碼此段文字,請先指定以下標頭:

Content-Transfer-Encoding: base64

然後,在電子郵件的內文區段,包含 base64 編碼的文字:

4KWn4KWv4KWt4KWoIOCkruClhyDgpLDgpYcg4KSf4KWJ4KSu4KSy4KS/4KSC4KS44KSoIOCkqOCl hyDgpKrgpLngpLLgpL4g4KSILeCkruClh+CksiDgpLjgpILgpKbgpYfgpLYg4KSt4KWH4KSc4KS+ IHwg4KSw4KWHIOCkn+ClieCkruCksuCkv+CkguCkuOCkqCDgpKjgpYcg4KS54KWAIOCkuOCksOCl jeCkteCkquCljeCksOCkpeCkriBAIOCkmuCkv+CkqOCljeCkuSDgpJXgpL4g4KSa4KSv4KSoIOCk leCkv+Ckr+CkviDgpJTgpLAg4KSH4KSo4KWN4KS54KWAIOCkleCliyDgpIjgpK7gpYfgpLIg4KSV 4KS+IOCkhuCkteCkv+Ckt+CljeCkleCkvuCksOCklSDgpK7gpL7gpKjgpL4g4KSc4KS+4KSk4KS+ IOCkueCliAo=
注意

在某些情況下,您可以在使用 Amazon 傳送的訊息Content-Transfer-Encoding中使用 8 位元SES。不過,如果 Amazon SES 必須對訊息進行任何變更 (例如,當您使用開啟並按一下追蹤 時),則 8 位元編碼的內容可能無法在送達收件人的收件匣時正確顯示。因此,您應該一律編碼非 7 位元的內容ASCII。

檔案附件

若要將檔案附加到電子郵件,您必須使用 base64 編碼來編碼附件。附件通常放置在專用MIME訊息部分中,其中包括下列標頭:

  • Content-Type - 附件的檔案類型。以下是常見 MIME Content-Type 宣告的範例:

    • 純文字檔案 - Content-Type: text/plain; name="sample.txt"

    • Microsoft Word 文件 - Content-Type: application/msword; name="document.docx"

    • JPG 映像Content-Type: image/jpeg; name="photo.jpeg"

  • Content-Disposition - 指定收件人的電子郵件用戶端應該如何處理內容。針對附件,此值為 Content-Disposition: attachment

  • Content-Transfer-Encoding - 過去用來編碼附件的方案。針對檔案附件,此幾乎一律為 base64

  • 編碼附件 - 您必須對實際附件進行編碼,并將其包含在附件標題下方的正文中,如範例中所示

Amazon SES接受最常見的檔案類型。如需 Amazon SES不接受的檔案類型清單,請參閱 Amazon SES 不支援的附件類型

使用 Amazon SES API v2 傳送原始電子郵件

Amazon SES API v2 提供 SendEmail動作,可讓您以設定內容類型為簡單、原始或範本時指定的格式撰寫和傳送電子郵件訊息。如需完整描述,請參閱 SendEmail。下列範例將指定raw使用原始電子郵件格式傳送訊息的內容類型。

注意

如需對 SendEmail 執行多重呼叫時提高電子郵件傳送速率的方法,請參閱 透過 Amazon SES 增加輸送量

訊息內文必須包含一封格式正確的電子郵件原始碼訊息,並使用適當的標題欄位與訊息內文編碼。雖然您可以在應用程式內手動建構訊息原始碼,但是使用現有的郵件程式庫來操作會更簡單。

Java

下列程式碼範例示範如何使用JavaMail程式庫和 AWS SDK for Java來撰寫和傳送原始電子郵件。

package com.amazonaws.samples; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.PrintStream; import java.nio.ByteBuffer; import java.util.Properties; // JavaMail libraries. Download the JavaMail API // from https://javaee.github.io/javamail/ import javax.activation.DataHandler; import javax.activation.DataSource; import javax.activation.FileDataSource; import javax.mail.Message; import javax.mail.MessagingException; import javax.mail.Session; import javax.mail.internet.AddressException; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeBodyPart; import javax.mail.internet.MimeMessage; import javax.mail.internet.MimeMultipart; // AWS SDK libraries. Download the AWS SDK for Java // from https://aws.amazon.com/sdk-for-java import com.amazonaws.regions.Regions; import com.amazonaws.services.simpleemail.AmazonSimpleEmailService; import com.amazonaws.services.simpleemail.AmazonSimpleEmailServiceClientBuilder; import com.amazonaws.services.simpleemail.model.RawMessage; import com.amazonaws.services.simpleemail.model.SendRawEmailRequest; public class AmazonSESSample { // Replace sender@example.com with your "From" address. // This address must be verified with Amazon SES. private static String SENDER = "Sender Name <sender@example.com>"; // Replace recipient@example.com with a "To" address. If your account // is still in the sandbox, this address must be verified. private static String RECIPIENT = "recipient@example.com"; // Specify a configuration set. If you do not want to use a configuration // set, comment the following variable, and the // ConfigurationSetName=CONFIGURATION_SET argument below. private static String CONFIGURATION_SET = "ConfigSet"; // The subject line for the email. private static String SUBJECT = "Customer service contact info"; // The full path to the file that will be attached to the email. // If you're using Windows, escape backslashes as shown in this variable. private static String ATTACHMENT = "C:\\Users\\sender\\customers-to-contact.xlsx"; // The email body for recipients with non-HTML email clients. private static String BODY_TEXT = "Hello,\r\n" + "Please see the attached file for a list " + "of customers to contact."; // The HTML body of the email. private static String BODY_HTML = "<html>" + "<head></head>" + "<body>" + "<h1>Hello!</h1>" + "<p>Please see the attached file for a " + "list of customers to contact.</p>" + "</body>" + "</html>"; public static void main(String[] args) throws AddressException, MessagingException, IOException { Session session = Session.getDefaultInstance(new Properties()); // Create a new MimeMessage object. MimeMessage message = new MimeMessage(session); // Add subject, from and to lines. message.setSubject(SUBJECT, "UTF-8"); message.setFrom(new InternetAddress(SENDER)); message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(RECIPIENT)); // Create a multipart/alternative child container. MimeMultipart msg_body = new MimeMultipart("alternative"); // Create a wrapper for the HTML and text parts. MimeBodyPart wrap = new MimeBodyPart(); // Define the text part. MimeBodyPart textPart = new MimeBodyPart(); textPart.setContent(BODY_TEXT, "text/plain; charset=UTF-8"); // Define the HTML part. MimeBodyPart htmlPart = new MimeBodyPart(); htmlPart.setContent(BODY_HTML,"text/html; charset=UTF-8"); // Add the text and HTML parts to the child container. msg_body.addBodyPart(textPart); msg_body.addBodyPart(htmlPart); // Add the child container to the wrapper object. wrap.setContent(msg_body); // Create a multipart/mixed parent container. MimeMultipart msg = new MimeMultipart("mixed"); // Add the parent container to the message. message.setContent(msg); // Add the multipart/alternative part to the message. msg.addBodyPart(wrap); // Define the attachment MimeBodyPart att = new MimeBodyPart(); DataSource fds = new FileDataSource(ATTACHMENT); att.setDataHandler(new DataHandler(fds)); att.setFileName(fds.getName()); // Add the attachment to the message. msg.addBodyPart(att); // Try to send the email. try { System.out.println("Attempting to send an email through Amazon SES " +"using the AWS SDK for Java..."); // Instantiate an Amazon SES client, which will make the service // call with the supplied AWS credentials. AmazonSimpleEmailService client = AmazonSimpleEmailServiceClientBuilder.standard() // Replace US_WEST_2 with the AWS Region you're using for // Amazon SES. .withRegion(Regions.US_WEST_2).build(); // Print the raw email content on the console PrintStream out = System.out; message.writeTo(out); // Send the email. ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); message.writeTo(outputStream); RawMessage rawMessage = new RawMessage(ByteBuffer.wrap(outputStream.toByteArray())); SendRawEmailRequest rawEmailRequest = new SendRawEmailRequest(rawMessage) .withConfigurationSetName(CONFIGURATION_SET); client.sendRawEmail(rawEmailRequest); System.out.println("Email sent!"); // Display an error if something goes wrong. } catch (Exception ex) { System.out.println("Email Failed"); System.err.println("Error message: " + ex.getMessage()); ex.printStackTrace(); } } }
Python

以下程式碼範例說明如何使用 Python email.mime 套件和 AWS SDK for Python (Boto) 來撰寫與傳送電子郵件原始碼。

import json import boto3 from botocore.exceptions import ClientError from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText from email.mime.application import MIMEApplication import os def boto3_rawemailv2(): SENDER = "Sender <sender@example.com>" RECIPIENT = "recipient@example.com" CONFIGURATION_SET = "ConfigSet" AWS_REGION = "us-east-1" SUBJECT = "Customer service contact info" ATTACHMENT = "path/to/customers-to-contact.xlsx" BODY_TEXT = "Hello,\r\nPlease see the attached file for a list of customers to contact." # The HTML body of the email. BODY_HTML = """\ <html> <head/> <body> <h1>Hello!</h1> <p>Please see the attached file for a list of customers to contact.</p> </body> </html> """ # The character encoding for the email. CHARSET = "utf-8" msg = MIMEMultipart('mixed') # Add subject, from and to lines. msg['Subject'] = SUBJECT msg['From'] = SENDER msg['To'] = RECIPIENT # Create a multipart/alternative child container. msg_body = MIMEMultipart('alternative') # Encode the text and HTML content and set the character encoding. This step is # necessary if you're sending a message with characters outside the ASCII range. textpart = MIMEText(BODY_TEXT.encode(CHARSET), 'plain', CHARSET) htmlpart = MIMEText(BODY_HTML.encode(CHARSET), 'html', CHARSET) # Add the text and HTML parts to the child container. msg_body.attach(textpart) msg_body.attach(htmlpart) # Define the attachment part and encode it using MIMEApplication. att = MIMEApplication(open(ATTACHMENT, 'rb').read()) # Add a header to tell the email client to treat this part as an attachment, # and to give the attachment a name. att.add_header('Content-Disposition','attachment',filename=os.path.basename(ATTACHMENT)) # Attach the multipart/alternative child container to the multipart/mixed # parent container. msg.attach(msg_body) msg.attach(att) #changes start from here strmsg = str(msg) body = bytes (strmsg, 'utf-8') client = boto3.client('sesv2') response = client.send_email( FromEmailAddress=SENDER, Destination={ 'ToAddresses': [RECIPIENT] }, Content={ 'Raw': { 'Data': body } } ) print(response) boto3_rawemailv2 ()