【问题标题】:Send thousands of emails with crontab in django and aws在 django 和 aws 中使用 crontab 发送数千封电子邮件
【发布时间】:2018-08-15 00:29:43
【问题描述】:

我有一个流程,每周发送大约 1500 封邮件。

我在django 命令中拥有它的过程,我计划将其放入crontab。该过程有一个循环,在该循环中验证用户是否想要接收电子邮件以及接收的语言,例如:

for user in users:
    # Check if user accept emails
    if user['send_mail']:
        # Get language to email
        lang = ""
        if user['lang'] == "es":
            lang = "es"
        elif user['lang'] == "fr":
            lang = "fr"
        else:
            lang = "en"

        email = user['email']

        # Send email
        send_mail()

1500 封邮件并不多,但我想让它具有可扩展性,因为邮件的数量取决于平台的注册用户数量。

我不知道它现在是否可以扩展或者使用redis queuecelery 更好。

我正在使用Amazon Simple Emails Service (SES)。

【问题讨论】:

  • 请不要使用队列发送电子邮件。电子邮件系统(根据 SMTP 规范的本质)是一个巨大的队列。有两种方法可以解决这个问题:要么在此框上使用本地邮件守护程序,将电子邮件转发出去并处理重试,要么使用为您提供休息接口(如 SES)的系统,它将为您重试。 Celery/Redis 不适合这项工作,因为 SMTP 从重试的角度来看需要大量客户端,而您不想自己编写代码。
  • @MatthewStory 我根本不同意,我不禁觉得你错过了问题的重点。是的,电子邮件是一种队列,但 SES 是一种 API,访问它需要时间;如果您尝试在 Django 视图中执行 1500 次 API 调用,它将超时。
  • @DanielRoseman 他正在将其移至 crontab ......那你为什么要使用 celery?另外,为什么您从根本上不同意?电子邮件不是一种队列,它们实际上是一个特定于域的优先级队列,具有非常粗糙的重试规范。
  • @MatthewStory 感谢您的回答。你能再解释一下吗:“这里有两种方法:要么在这个盒子上使用一个本地邮件守护程序,它将转发电子邮件并处理重试,要么使用一个为你提供休息接口的系统(如 SES)这将为您重试”我不明白现在这样是否可以,或者我是否必须进行更改以使其可扩展?谢谢!
  • @YannicHamann 我将在今天晚些时候尝试撰写对此的答案以更详细地介绍它,但简短的回答是,根据定义,SMTP 是一个异步任务队列,它具有非常具体和复杂的重试规则客户端必须实现,因此使用 celery 是多余的,并且还可能导致不正确的客户端实现。这就是为什么我通常更喜欢使用本地中继邮件程序,保证本地交付(如 nullmailer)或使用来自 cron 的 REST 接口(如 SendGrid 或 SES)。

标签: python django amazon-web-services amazon-simple-email-service


【解决方案1】:

这里有两个不同的问题需要处理:

首先,虽然发送 1500 封电子邮件很容易,但是否会收到这 1500 封电子邮件是一个复杂的现实。您的电子邮件很容易被阻止或转移到垃圾邮件文件夹。某些邮件服务可能会阻止您的整个域。为了限制这些困难的可能性,您需要正确设置 DKIM 和 SPF 记录。商业邮件发件人还会做其他事情来保持事情顺利进行。因此,如果您对接受这一挑战不感兴趣,那么最好使用像 SES 这样的专业服务。

当然,您也可以使用 postfix 或任何其他邮件中继软件在本地设置您自己的邮件服务器,甚至在同一台机器上。设置您自己的 DNS 记录并将邮件直接发送给收件人,无需 SES 或其他任何人处理。但您必须处理任何垃圾邮件拦截器问题。

其次,假设您使用 SES,您必须确保您的所有电子邮件都安全地从您自己发送到亚马逊。这就是麻烦出现的地方。您不想生成一半的电子邮件并交付它们,然后由于网络中断,有问题..并且无法仅发送那些没有发送的邮件全部重发。编写完美的代码可能有点棘手。

从技术上讲,最简单的解决方案是安装一个本地 SMTP 中继服务器(例如 postfix),并将 Amazon 配置为它的“智能主机”。将 django 配置为使用“localhost”作为其 SMTP 服务器。

有了这个,当你的 cron 作业运行时,它只需要几秒钟,因为所有的电子邮件都会直接进入你本地驱动器上的 postfix 目录并在那里排队。

然后postfix,因为它配置了SES的SMTP服务器作为它的smarthost(有时称为智能中继),所以不会直接向收件人发送任何邮件,而是将所有邮件转发给SES,以便投递给最终的收件人.如果这样做有任何问题,postfix(或您喜欢的任何邮件中继软件)将重试每条消息,直到一切正常。

它就是为此而设计的,它已经过尝试、测试、工作......

所以这对你来说是最简单的路径。

如果您选择使用 SES REST API,那么您的代码有责任确保将每条消息准确地传送到亚马逊一次且仅一次。如果您循环浏览 1000 封电子邮件,然后出现网络故障或崩溃,并且您未能发送最后 500 封电子邮件,那么您的代码将无法从该电子邮件中恢复,而无需再次重新发送前 1000 封电子邮件。为此,是的,排队系统很有用。芹菜或只是 RabbitMQ 本身可以工作。或者只是通过在您的数据库中存储需要发送哪些消息的记录来创建一个队列,然后在发送每封电子邮件时删除这些记录。

但是编写在任何情况下都能完美运行的代码可能会很棘手。有时重新发明轮子是可以的。有时你需要一个更好的轮子:) 但在这种情况下,我认为你最好使用 SMTP 中继服务器。

【讨论】:

  • 中继服务器几乎总是要走的路。
  • 太好了,回答,我将研究如何实现 SMTP 中继服务器。我不明白的是:因为我现在使用它在 settings.py 中配置 SES SMTP 并使用 send_mail 函数。除了丢失电子邮件之外,它是否可扩展或者我会遇到什么问题?服务器能饱和吗?
  • @MatthewStory 我明白了,我不明白的是我现在如何拥有我的配置和代码。
  • 网上有很多关于如何设置postfix通过SES中继邮件的贴子。这是其中之一。 tothenew.com/blog/… 但我建议你看几个。除了确保 postfix 将所有邮件转发到 SES 之外,您还需要确保 postfix 不会将其 smtp 暴露给外界!为此,请确保您的配置中有inet_interfaces = 127.0.0.1!很重要。否则全世界都可以通过您的 SES 帐户发送垃圾邮件。
  • 要测试您的 smtp 服务器是否未暴露,首先尝试(在您的服务器上)telnet localhost 25.. 您应该会收到来自 postfix 的问候消息。然后使用服务器的外部 IP 地址尝试相同的操作。它不应该连接。
猜你喜欢
  • 2017-05-25
  • 1970-01-01
  • 2012-04-09
  • 1970-01-01
  • 1970-01-01
  • 2015-12-05
  • 2018-06-15
  • 2011-02-18
  • 2013-08-09
相关资源
最近更新 更多