AWS 的 SES (Simple Email Service) 可以提供邮件收发服务。对于邮件收发的反馈,如 Bounce message, 可以发送到 SNS (Simple Notification Service) 作进一步处理。SNS 可以指定某个邮件地址作为订阅者,将消息发送到该邮箱中。然而,SNS发出来的邮件是 JSON,可读性不好,例如:
怎么能让这个提醒邮件变得更加友好呢? SNS目前不支持自定义邮件格式。一个思路是,将 SNS 的消息发送到 Lambda 上,让 Lambda 处理好格式后,再发送到指定邮箱。即 SES -> SNS -> Lambda -> SES.
创建 SNS Topic
创建一个SNS Topic, 比如名字叫"email-notify".
创建 Lambda Function
使用 Lambda 的 Blueprints ses-notification-python 作为模板,创建以下 Lambda Function.
这里主要修改了 handle_delivery 这个 Handler, 期望每次 SES 发送邮件后,都会触发这个 Handler, 将相关信息发送到管理员邮箱。
import json
import boto3
from botocore.exceptions import ClientError
def lambda_handler(event, context):
message = json.loads(event['Records'][0]['Sns']['Message'])
notification_type = message['notificationType']
handlers.get(notification_type, handle_unknown_type)(message)
def handle_bounce(message):
message_id = message['mail']['messageId']
bounced_recipients = message['bounce']['bouncedRecipients']
addresses = list(
recipient['emailAddress'] for recipient in bounced_recipients
)
bounce_type = message['bounce']['bounceType']
print("Message %s bounced when sending to %s. Bounce type: %s" %
(message_id, ", ".join(addresses), bounce_type))
def handle_complaint(message):
message_id = message['mail']['messageId']
complained_recipients = message['complaint']['complainedRecipients']
addresses = list(
recipient['emailAddress'] for recipient in complained_recipients
)
print("A complaint was reported by %s for message %s." %
(", ".join(addresses), message_id))
def handle_delivery(message):
message_id = message['mail']['messageId']
delivery_timestamp = message['delivery']['timestamp']
header_from = message['mail']['commonHeaders']['from'][0]
header_to = message['mail']['commonHeaders']['to'][0]
print("Message %s was delivered successfully at %s" %
(message_id, delivery_timestamp))
SENDER = "feichashao-ses <feichashao@gmail.com>"
RECIPIENT = "feichashao@qq.com"
AWS_REGION = "us-west-2"
SUBJECT = "Amazon SES Test (SDK for Python)"
BODY_TEXT = ("Amazon SES Test (Python)\r\n"
"This email was sent with Amazon SES using the "
"AWS SDK for Python (Boto)."
)
BODY_HTML = """<html>
<head></head>
<body>
<h1>Email Delivery</h1>
<p>From: {}</p>
<p>To: {}</p>
</body>
</html>
""".format(header_from, header_to)
CHARSET = "UTF-8"
client = boto3.client('ses',region_name=AWS_REGION)
try:
#Provide the contents of the email.
response = client.send_email(
Destination={
'ToAddresses': [
RECIPIENT,
],
},
Message={
'Body': {
'Html': {
'Charset': CHARSET,
'Data': BODY_HTML,
},
'Text': {
'Charset': CHARSET,
'Data': BODY_TEXT,
},
},
'Subject': {
'Charset': CHARSET,
'Data': SUBJECT,
},
},
Source=SENDER,
)
# 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'])
def handle_unknown_type(message):
print("Unknown message type:\n%s" % json.dumps(message))
raise Exception("Invalid message type received: %s" %
message['notificationType'])
handlers = {"Bounce": handle_bounce,
"Complaint": handle_complaint,
"Delivery": handle_delivery}
在 Designer 中,将刚刚创建的 SNS 作为 Trigger。
创建 SES 服务
上面两个都是为 SES 服务的。现在,创建一个 SES 服务。认证一个 Domain 作为邮件发送方,认证一个 Email 作为邮件接收方。
点进 SES 的 Domain(以 feichashao.com 为例),点开 Notification 一栏,点击 Edit Configuration, 将 Deliveries 选择为上面的 SNS topic,如 "email-notify".
回到 Domain 的界面,点击 Send a Test Email 进行测试。发送者是 test1@feichashao.com,收件人是 feichashao@gmail.com。在邮件发送成功后,Lambda 应该会收到 SNS 的信息,然后 Lambada 会把 JSON 整理后,发送到管理员邮箱 feichashao@qq.com.
From: test4@feichashao.com
To: feichashao@gmail.com