AWS SES:如何发送大量电子邮件(一次 > 10000 封)

AWS SES: how to send a large amount of emails (> 10000 at a time)

我正在构建一个电子邮件发送服务(lambda,Nodejs),它将同时向地址列表发送电子邮件。

由于要求:每个地址接收的邮件内容不同,我不能在一个请求中发送多封邮件,而是一封一封发送。

_array = ... // list of address + html content, > 10000 records
for (var i = 0; i < _array.length; i++) {
    var params = {
        Destination: {/* required */
            ToAddresses: [_array[i].email]
        },
        Message: {/* required */
            Body: { /* required */
                Html: {
                    Data: _array[i].html,
                    Charset: 'UTF-8'
                },
            },
            Subject: { /* required */
                Data: 'Your order detail', /* required */
                Charset: 'UTF-8'
            }
        },
        Source: "mytestemail@email.com"
    }

    let send = await ses.sendEmail(params).promise();

}

目前,我没有那么大的数据可以测试,但我测试了 100-200 封电子邮件,它正在运行,并且需要 15-40 秒才能完成发送电子邮件。从数学上讲,10000 需要超过 25 分钟才能完成任务。因此,这种方法不可扩展,因为 lambda 超时限制为 15 分钟

如有更好的方法或建议,我们将不胜感激。

编辑:

来自@Thales Minussi 的解决方案很棒,我实现了它并且它正在运行。我将其标记为答案,但我仍然欢迎所有解决此问题的最佳做法。快乐地分享、学习、编码

不推荐:可以做的是并行化sendEmail电话。因此,您可以创建一大堆 Promises,然后使用 await Promises.all(yourPromisesArray),因此 Node.js 会根据您的 Lambda 函数 [=53] 机器上可用的内核数量,尽最大努力优化流程=]s at,意味着要充分利用它,您需要将 Lambda 的 RAM 内存设置为 3GB(机器与 RAM 的数量成正比,这意味着您设置的 RAM 越多,机器越好您的代码 运行s on)。但这仍然是 错误 ,因为现在我们谈论的是 10000 e-mails,但是如果这个数字增长到 100000 怎么办? 1000000?它只是一个无法扩展到足以满足需求增长的解决方案,所以这还不够。另一件事是,如果出现问题(比如一个 Promise 失败),那么就很难恢复。

推荐: 我建议您使用 SQS 将创建 e-mail 主体的函数从实际发送它的函数,长话短说,而不是像上面那样调用 await ses.sendEmail(params).promise(),而是将此消息放入 SQS 队列(遵守每条消息 256KB 的限制)并订阅另一个 Lambda到这个 SQS 队列。每个 Lambda 最多可以从 SQS 读取一批 10 条消息(每条消息可以包含许多 e-mails),这将显着加快该过程,特别是因为默认情况下,您的 Lambda 函数将扩展以满足需求。

让我们运行做一个简单的数学计算:如果您向 SQS 发送 100 条消息并且每条消息有 10 e-mails,这意味着,在最佳情况下,将启动 10 个 Lambda,每个消耗一个每批 10 条消息,但由于每条消息包含 10 e-mails,每个 Lambda 将处理 100 e-mails,因此您将在眨眼间处理 1000 e-mails!

重要的是要注意,并非所有 Lambda 每次都会选择 10 个批次,它们可能会选择较小的批次,因此可能会同时启动 10 个以上的 Lambda 函数,但是我想你明白了并行处理的想法

编辑:因为e-mails可以由大量有效负载(图像、长字符串等)组成,我建议你只将相关信息发送到 SQS 队列以优化负载大小。如果您需要处理图像或一些 pre-defined 模板,只需在 S3(或您可能使用的其他存储)中发送它们各自的位置,这样实际负责发送 e-mails 的 Lambda 就是那个获取该信息并将其添加到正文中。从本质上讲,您发送给 SQS 的消息应该只包含元数据,以使负载尽可能轻,这样您就可以充分利用 256KB 的限制。这样的事情应该足以让你离开地面:

{
    "to": "to@email.com",
    "images": ["s3://bucket/image.jpg", "s3://bucket/image2.jpg"],
    "template": "s3://bucket/template.html"
}

架构流程

太晚了,但这是我想出的架构。 cloudwatch 规则在特定时间触发。它调用 lambda。 lambda 获取在这个特定时间要发送的所有电子邮件的计数,将其分成 10 个块,然后对于每个 10 个块,它发布到 SNS "send_email_topic" 的主题,该主题进一步调用发送的 lambda电子邮件。从 SNS 调用的每个 lambda 将接收块大小,在我们的例子中为 10 和偏移值。调用的 lambda 命中数据库并获取要发送的电子邮件行,给定块大小作为限制和偏移量(偏移量以避免不同的 lambda 发送相同的电子邮件)并发送电子邮件。每个调用的 lambda 将发送最多 10 封电子邮件。

失败

如果电子邮件发送失败,电子邮件 ID 将被发送到队列中。 SQS 收到消息后将发布到不同主题的 SNS "retry_email_send",这将再次调用 lambda,但略有不同的 lambda 接收要重试的电子邮件的电子邮件 ID,从数据库中获取单个电子邮件并重试

重要说明

  1. 您需要增加 Lambda 的超时时间。 300 秒是最大限制。
  2. SES 可能不适合其配额限制,您可能需要专用的 SMTP 服务器。
  3. 您也可以选择 SendGrid,因为它无需任何设置即可提供所有这些,除非您尝试制作类似于 sendgrid 本身的东西