亚马逊AWS官方博客

新域名如何使用 SES 极限发送邮件

本文场景及目标读者

本文目标是快速提高邮件发送方在邮件 ISP 端的信誉,以期达到快速升高邮件发送限额。

目前市场上大多邮件发送产品都是针对大规模邮件发送的。对于新域名,或者从来没有作为邮件发送域的域名,在使用任何邮件发送服务时,都会遭遇限流问题,尤其是突发的需要大规模发送邮件的场景,这种情况可以参考本文进行处理。

本文不适合无 ISP 限流的场景,例如发送方在 ISP 端已经有良好信誉,单纯要提高邮件发送吞吐。

SES 邮件发送简介

AWS SES(Simple Email Service)是一项由 Amazon 提供的电子邮件发送服务。它允许开发人员通过编程方式发送电子邮件,并提供了一系列功能来管理和跟踪电子邮件的发送情况。AWS SES 的一些主要特点和优势包括: 简单易用,自动扩展,高可用性和可靠性,支持多种电子邮件格式,详细的分析和报告功能,灵活的定价。

在整个邮件发送的过程中,AWS SES 作为邮件发送服务,将邮件发送给邮件服务提供商(ISP),最终收件人通过应用获取到邮件。在这个链路中,AWS SES 和 ISP 都会基于自己的规则对邮件进行检查和限流,以保证收发件人以及自身的利益。

SES 限制

  • 沙箱:新申请的发件主体会在沙箱中进行发送,收件人以及发送量都会有限制。
  • Quota:在申请移出沙箱后,会有每日最大发送邮件数以及每秒最大发送邮件数限制,可以申请提额
  • 投诉和退回率限制:当邮件的退回率超过 5%,投诉率超过 1%,邮件发送所在的账号处于风险状态,需要和 support  团队沟通防止 SES 被禁用的情况。

邮件服务商(ISP)限制

包括 Gmail,Yahoo 在内的大的邮件服务提供商,所有 ISP 都会基于自己的规则,对收到的邮件数量进行限流,限流包含不同的时间维度。以 Gmail 为例,会有基于分钟,小时和天维度的邮件接收量的限制。ISP 的规则包含的主要内容以及应对方式如下表所示:

ISP 规则包含的元素 应对方式
发送邮件的 IP 信誉 AWS 提供共享 IP 和独占 IP 来满足 ISP 对于 IP 的声誉要求,对于本文状况,我们使用共享 IP 来缩短发送过程
发送邮件的域名信誉 对于新域名,需要一个“培养”信誉的过程,是本文要解决的问题
发件主体的验证信息 包括 SPF,DKIM 和 DMARC 等认证方式,SES 提供满足要求的具体方法
ISP 的合规要求,如 Spam 邮件内容等是否满足 ISP 合规要求,如必须的邮件 header,一键退订,内容重复等
回弹(bounce)和投诉率 发送者需要自己控制收件人的质量

参考:Gmail 邮箱规则链接

方案介绍

邮件发送方案

方案介绍

  1. 我们把发送邮件的应用部署在“邮件发送”的 EC2 上。
  2. 邮件发送服务把需要发送的邮件从 Aurora Serverless 中拉取出来。使用 serverless 是因为邮件数据库并不需要经常访问,从而不必使用传统的数据库,达到省钱的目的。
  3. 在邮件发送服务中,循环发送邮件地址,并通过对 email 的 metric 的监控,控制发送的速率。

当我们在 ISP 端的 quota 不明的情况下,非常容易出现 ISP 对我们的发送速率进行限流。当限流发生时,很可能出现 ISP 对发送不反馈的情况。这个时候,通过简单的 Bounce Rate 进行监控是不够的。如下图所示:

在图中左侧的第一个波峰,我们看到黄色的 Send 指标和紫色的 Delivery 非常贴近,说明 ISP 对我们的反馈非常迅速,邮件发送非常顺利。在时间点 15:40 的时候,黄线和紫线出现了较大的分离,说明 ISP 对发送已经开始了限流,此时需要降低发送速率,甚至停止发送。

在上面图中,15:45 之后后续的 Delivery 指标逐渐增多,说明 ISP 在对发送的邮件延迟发送/确认。

示例代码:

 for row in results:
            time.sleep(send_frequency)
            currenttime = datetime.now(timezone.utc)
            timediff = currenttime - starttime
            if (timediff.total_seconds()/float(60) >= 1): #检查频率
                result = checkPongRate(currenttime)
                starttime = currenttime
                if (result is not None):
                    if(result > 0.96):
                        send_frequency*=0.8
                    if(result < 0.90):
                        if(send_frequency < 0.5):
                            send_frequency = 0.5
                        else:
                            send_frequency*=1.5 #increase 20% latency
                    if(result < 0.80):
                        break

这里的 checkPongRate 就是调用 CloudWatch 的指标,获取当前的 Delivery Rate。

在使用这套方案后,我们的效果如下图所示:

在 14:33 分时,发生了 Send 与 Delivery 的背离,程序在 14:35 左右自动停止了发送。

当信誉值不成为阻碍时,Send 和 Delivery 表现为一个逐渐升高的曲线:

邮件统计方案

当遭遇到延迟发送的情况时,我们会希望看到是哪些 ISP 导致的延迟(一般情况下,大的 ISP 会导致延迟发送,因为它也是在邮件发送列表中占比比较大的),持续向限流的 ISP 发送邮件会遭遇定时的大规模退信,所以清楚哪些 ISP 导致的限流/延迟发送,对我们灵活的发送策略至关重要,我们可以避开限流的 ISP,暂时发送其它 ISP。

在这个方案中,我们使用 ConfigurationSet 对邮件的生命周期事件进行了跟踪,所有的事件都转发到 SNS 服务,在 Lambda 程序中进行处理。为了防止突然增大的邮件数量导致 Lambda 的并发问题,我们设置了的 DLQ(Dead Letter Queue)作为应急处理,防止事件丢失。最终,把邮件的状态写入 Aurora Serverless 中,实现对每封邮件的追踪。同时,也可以简单的 SQL 语句,查询哪些 ISP 出现了限流问题。

方案总结

在这套方案中,使用一台 m5.2xlarge 服务器,可以实现峰值 1700 封/分钟的发送速率(单线程),由于使用了大量无服务器组件,每日发送量在 10 万的情况下,成本在 $30/天左右。可以快速实现“培养”新发送域名,或者应对突然大规模发送邮件的场景。

当前方案可以考虑提升的点:

  • 定时启动。可以通过 CloudWatch 的定时功能,每隔 1 小时调用一次邮件发送功能,实现自动持续的“声誉培养”。
  • 在发送过程中,通过对发送情况的查询,获取每个 ISP 是否到达限流,从而在当前发送的 batch 中过滤掉已经限流的 ISP(大多数情况下不需要考虑这种情况)。

当域名已经有足够声誉, 可以考虑转移到 pinpoint 或者自建邮件发送平台, 实现大规模邮件发送, 配合 AWS SES VDM 实现邮件发送情况的监控。

附录

https://aws.amazon.com/blogs/messaging-and-targeting/the-four-pillars-of-email-reputation/

本篇作者

孙标

亚马逊云科技资深解决方案架构师。拥有多年金融,移动互联网研发及数字货币交易所架构经验。