本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。
使用 Amazon SES API v2 发送原始电子邮件
您可以使用指定内容类型的 Amazon SES API v2 SendEmail
操作,使用原始电子邮件格式raw
向收件人发送自定义消息。
简单邮件传输协议 (SMTP) 通过定义邮件信封及其部分参数来指定电子邮件将如何发送,但它本身与邮件内容无关。相反,Internet 邮件格式 (RFC 5322) 定义了如何创建邮件。
根据 Internet 邮件格式规范,每封电子邮件都包含标题和正文。标题包含邮件元数据,正文包含邮件本身。有关电子邮件标题和正文的更多信息,请参阅Amazon SES 中的电子邮件格式。
使用 MIME
SMTP 协议最初设计用于发送仅包含 7 位 ASCII 字符的电子邮件。此规范使得 SMTP 不足以应对非 ASCII 文本编码(如 Unicode)、二进制内容或附件。多用途 Internet 邮件扩展标准 (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 段的末尾,在边界字符串的开头和末尾处放置两个连字符。
MIME 编码
为了保持与旧系统的兼容性,Amazon SES 遵循 RFC 2821 中定义的 SMTP 7 位 ASCII 限制。如果要发送包含非 ASCII 字符的内容,则必须将这些字符编码为使用 7 位 ASCII 字符的格式。
电子邮件地址
电子邮件地址字符串必须为 7 位 ASCII 字符。如果您希望向或从某个地址的域部分中包含 Unicode 字符的电子邮件地址发送邮件,则必须使用 Punycode 对域进行编码。不允许在电子邮件地址的本地部分 (@ 符号前面的部分) 中使用 Punycode,也不允许在“易记发件人”名称中使用。如果您想要在“易记发件人”名称中使用 Unicode 字符,您必须使用 MIME encoded-word 语法编码“易记发件人”名称,如使用 Amazon SES API v2 发送原始电子邮件中所述。有关 Punycode 的更多信息,请参阅 RFC 3492。
此规则仅适用于您在邮件信封中指定的电子邮件地址,不适用于邮件标头。当您使用 Amazon SES API v2 SendEmail
操作时,您在Source
和Destinations
参数中指定的地址分别定义信封发件人和收件人。
要对邮件标头进行编码,请使用 MIME encoded-word 语法。MIME encoded-word 语法使用以下格式:
=?charset
?encoding
?encoded-text
?=
encoding
的值可以是 Q
或 B
。如果编码值为 Q
,则 encoded-text
的值必须使用 Q 编码。如果编码值为 B
,则 encoded-text
的值必须使用 base64 编码。
例如,如果您要在电子邮件的主题行中使用字符串“Як ти поживаєш?”,那么您可以使用以下任一编码:
有关 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 SES 发送的邮件中使用 8 位 Content-Transfer-Encoding
。但是,如果 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
发送消息的内容类型。
邮件正文必须包含格式正确的原始电子邮件,后者具有适当的标头字段和邮件正文编码。尽管能够在应用程序内手动构建原始邮件,但使用现有邮件库执行此操作轻松得多。
- 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 os
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
# Replace sender@example.com with your "From" address.
# This address must be verified with Amazon SES.
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.
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.
CONFIGURATION_SET = "ConfigSet
"
# If necessary, replace us-west-2 with the AWS Region you're using for Amazon SES.
AWS_REGION = "us-west-2
"
# The subject line for the email.
SUBJECT = "Customer service contact info"
# The full path to the file that will be attached to the email.
ATTACHMENT = "path/to/customers-to-contact.xlsx
"
# The email body for recipients with non-HTML email clients.
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></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"
# Create a new SES resource and specify a region.
client = boto3.client('ses',region_name=AWS_REGION)
# Create a multipart/mixed parent container.
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)
# Add the attachment to the parent container.
msg.attach(att)
#print(msg)
try:
#Provide the contents of the email.
response = client.send_raw_email(
Source=SENDER,
Destinations=[
RECIPIENT
],
RawMessage={
'Data':msg.as_string(),
},
ConfigurationSetName=CONFIGURATION_SET
)
# Display an error if something goes wrong.
except ClientError as e:
print(e.response['Error']['Message'])
else:
print("Email sent! Message ID:"),
print(response['MessageId'])