为SES配置SNS Event追踪每一封发送的状态

一、背景

AWS Simple Email Service是用于大规模发送推广邮件的服务,用于支撑会员系统等合理合法的邮件群发。

SES的最佳实践是:每个邮件地址调用1次SES接口,单独发送一个唯一的地址。参考如下介绍。

发送限制基于的是收件人而不是电子邮件。例如,一封包含 10 个收件人的电子邮件占用 10 份配额。但是,建议不要在一次 SendEmail 调用中向多个收件人发送电子邮件,因为如果对 Amazon SES 的调用失败(例如,请求格式错误),整个电子邮件都将被拒绝,没有任何收件人能收到预期的电子邮件。我们建议您为每个收件人调用一次 SendEmail

https://docs.aws.amazon.com/zh_cn/ses/latest/DeveloperGuide/manage-sending-limits.html

SES默认是只显示管理整个domain的状态,包括邮件总数、退信比例等。如果希望追踪单封邮件发送,可以使用如下办法。

二、设置SNS主题并使用邮件订阅主题

首先设置一个SNS主题。进入SNS服务,添加一个新主题,主题名字自选。

添加主题完成后,再其下添加订阅。点击添加订阅。

在添加订阅中,我们选择订阅的协议。本文档为了方便演示,且更加直观,将选择EMAIL-JSON格式作为SNS订阅发送状态的渠道。这意味着,SES发送一封邮件后,将向本SNS订阅者的邮箱中发送一个JSON文件,其中包含当前这份邮件是否发送成功的状态。

注意:如果是用于生产环境不要使用邮件订阅,而是将SQS队列服务订阅到本SNS主题,或者使用Lambda订阅,使用应用程序代码继续处理后续的发送状态。

输入订阅者的邮箱后,如果此邮箱是第一次作为订阅者,SNS会给此邮箱发送一封确认邮件,邮箱的所有人需要点击这份邮件里边的连接方可成功的订阅。

订阅完成。

三、设置配置集

注:2021年11月更新:SES控制台界面已经升级,选项位置有所不同,请参考最新官方文档。

在SES中找到配置集选项。点击新建配置集。

进入配置集后,添加新的事件,可以看到支持三种:Cloudwatch、Kinesis、SNS。Cloudwatch的作用是生成报表,Kinesis可以流式的采集数据;SNS即发送到标志通知服务,然后由SNS再根据订阅者决定信息发送目标。

接下来选择要订阅的通知类型,包括发送成功、失败、退信等。在下方选择SNS的topic。请同时订阅第一行的这几种状态。

其中,所有邮件都会先经历第一个状态:Send。如果是成功,第二个状态将收到delivery。如果退信,将收到Reject或者Bounce。

配置完成。

四、发送邮件测试

为了发起测试,我们可以使用AWS控制台图形界面,向SES内置的邮箱模拟器发送。点击这里访问使用文档。

如上截图,当需要测试不同的事件的时候,就可以把目标地址写为邮件模拟器提供的这几个测试地址。然后系统会根据刚才的设置,生成SNS通知,给出发送信息的反馈。

首先我们来测试发送成功场景,收件人地址使用:success@simulator.amazonses.com 。进入SES控制台,选中域名,选择发送邮件。选择使用RAW格式。然后在其中手工加入一行:

X-SES-CONFIGURATION-SET: ConfigSet

这行配置的作用是,在发送时候指定配置集,请把它替换为刚才创建配置集时候的名字。如下截图。

点击发送后,我们去看发送成果。

2021年11月更新:SES界面已经更新,本章节所提示的邮箱模拟器的地址不用在人工输入,直接在界面上选择即可发送。在发送同时,也可以通过界面上的下拉框选取配置集,也不在需要人为添加邮件头了。

可以看到SES分别将发送和投递成功两个Event返回给了SNS。SNS又将这两个Event的以订阅为Email-JSON的方式发送到邮箱。检查订阅邮箱,里边可以看到两封邮件。第一封是send(发送),第二封是成功(deilivery)。

接下来我们再验证一下退信的场景。

再次启动发件器,目标地址改为邮箱模拟器上的退信地址:bounce@simulator.amazonses.com ,然后执行发送。

现在查看SNS订阅邮箱,发现里边还会获得两个通知,第一个通知是发送(sent),第二个通知是被退信,且退信理由是SMTP服务器返回550代码,用户邮箱不存在。(当然这是AWS SES的邮箱模拟器模拟出来的退信效果)

由此,就实现了跟踪每一封邮件状态。

四、生产环境建议的建议

以上方法展示了SES如何通过Event事件的订阅机制,跟踪每一封邮件发送结果。以上环节仅是Demo,如果用于生产环境,还会有一些差异。

首先生产环境下发送邮件的方式是代码调用API执行,而非本文做实验通过AWS图形控制台发送测试邮件。使用代码通过AWS SES API发送邮件的样例可参考这里的地址有完整sample代码,包含Java和Python等常用代码。

第二是大规模发送邮件,要核实发送状态,不太可能通过Email方式订阅SNS主题的方式来查看投递状态日志。

推荐采用的方案是:

注:2021年11月更新。

(1)在SES界面上配置投递状态,将本域名的所有发送日志输出目标配置为SNS。然后在应用程序内订阅SNS Topic,并获取SNS的通知。这一步需要异步处理,因为从开始发送、投递、退信等各个阶段都有一定时间间隔,因此需要异步处理。本方法简单高效,缺点是不能区分本域名下不同发送需求(例如验证码、广告),且只能追踪退信等三个状态,不能追踪更多状态。

(2)从SES的配置集(Configuration Set)配置中,将发送日志输出到SNS。本过程与上一个方案一样都需要使用异步机制。增加了配置集的好处是可以处理不同发送需求,分别在发送验证码、广告等不同类型的邮件时候,加载对应的配置集,即可使用不同的日志策略。例如验证码无需追踪打开状态,广告邮件可以在配置集中增加对“打开”、“投诉”等状态的追踪。

(3)从SES配置集还可以输出日志CloudWatch和Kinesis,如果选择Kinesis filehose可将日志写入S3,再调用Athena运行SQL脚本查询日志,并完成后续逻辑。此外,也可以使用Lambda订阅SNS,然后通过lambda将发送成功和失败的地址和状态(元数据)写入到DynamoDB,以方便后期调阅。DynamoDB上打开生命周期,删除大于30天的发送记录。

以上多种日志处理方式可并行使用,供开发和架构设计参考。选择哪些方式并无绝对标准答案,可根据发送类型、发送规模、分析实效性、开发复杂度等多种因素进行选择。