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

时间:2019-05-14 10:09:12

标签: node.js aws-lambda amazon-ses

我正在构建电子邮件发送服务(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的解决方案很棒,我实现了它并且正在工作。我将其标记为答案,但是我仍然欢迎所有最佳实践解决此问题。开心地分享,学习和编码

2 个答案:

答案 0 :(得分:4)

不推荐使用 :您可以可以做的是使sendEmail调用并行化。因此,您可以创建大量Promises,然后使用await Promises.all(yourPromisesArray),以便Node.js会根据Lambda函数运行所在的计算机上可用内核的数量,尽最大努力优化流程。要充分利用它,您需要将Lambda的RAM内存设置为3GB(计算机与RAM量成正比,这意味着您设置的RAM越多,代码运行的机器就越好)。但这仍然是有问题的,因为现在我们谈论的是10000封电子邮件,但是如果这个数字增加到100000怎么办? 1000000?这只是一个解决方案,其规模不足以满足其增长的需求,因此这还不够。另一件事是,如果出现问题(例如Promise失败),则很难恢复。

推荐: 相反,我建议您使用SQS将创建电子邮件正文的功能与实际发送电子邮件的功能分离开简短的说,不是像上面那样调用await ses.sendEmail(params).promise(),而是将这条消息放入SQS队列中(遵守每条消息的256KB限制),然后向该SQS队列订阅另一个Lambda。每个Lambda最多可以从SQS读取10条消息(每条消息可以包含许多电子邮件),这将大大加快该过程,尤其是因为默认情况下,您的Lambda函数可以扩展以满足需求。

让我们进行一个简单的数学运算:如果您向SQS发送100条消息,并且每条消息都有10封电子邮件,这意味着,在最佳情况下,将增加10个Lambda,每个Lambda消耗一批10条消息,但每邮件包含10封电子邮件,每个Lambda将处理100封电子邮件,因此,您眨眼即可处理1000封电子邮件!

重要的是要注意,并不是所有的Lambda每次都会拾取10个批次,它们可能会拾取较小的批次,因此有可能同时启动了10个以上的Lambda函数,但我认为您会并行处理的想法

EDIT :由于电子邮件可能包含大量有效负载(图像,长字符串等),因此我建议您仅将相关信息发送到SQS队列,以优化有效负载大小。如果您需要处理图像或一些预定义的模板,只需在S3(或您可能使用的其他存储设备)中发送它们各自的位置,以便实际上负责发送电子邮件的Lambda就是获取该信息的那个。并将其添加到身体。本质上,您发送到SQS的消息应仅包含元数据,以使有效负载尽可能轻便,因此您可以从256KB的限制中受益。这样的事情足以让您动身:

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

答案 1 :(得分:-1)

建筑流

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

失败

如果电子邮件失败,则电子邮件ID将发送到队列。收到邮件的SQS将在另一个主题“ retry_email_send”上发布到SNS,该主题将再次调用lambda,但稍有不同的lambda会接收要重试的电子邮件的电子邮件ID,从数据库中获取单个电子邮件并重试

主要注释

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

enter image description here