如何在Python中快速发送邮件给数十万收件人,且每个收件人都显示在邮件头中?

4 投票
2 回答
6576 浏览
提问于 2025-04-17 07:42

我在找方法用Python发送大量邮件(成千上万封)。我有一个收件人列表(在一个文件里),想给他们每个人都发一封邮件。我希望每个收件人在邮件头里都能显示为收件人,而不是抄送或密送。我的解决方案是给每个人单独发送邮件,而不是一次性发给所有人。我做了一些工作如下:(我用了 smtplibthreading):

class SendMail(threading.Thread):
  def __init__(self, from, to, subject, message):
     self.from = from
     self.to = to
     self.subject = subject
     self.message = message 
  def run(self):
    try:
                msg = MIMEMultipart('alternative')
                msg['Subject'] = self.subject
                msg['From'] = self.from
                msg['To'] = self.to
                msg.attach(MIMEText(self.message , 'html'))
                server = smtplib.SMTP()              
                server.connect('xxxxx', 25)
                server.login('cxxxxx', 'yyyyyy')                
                server.sendmail(self.from, self.to, msg.as_string())
    except:
          pass

def sendmail():
   f = open('recipients','w')
   from = "me@mail.test"
   subject = "hello"
   message = "Hello Hello"
   for line in f.readlines():
      t = SendMail(from, line, subject, message)
      t.run()
   f.close()

这个方法可以用,但速度很慢(大约每秒6封邮件)。所以请帮我想办法让它快一点。或者给我推荐其他方法来完成这个任务。非常感谢!

2 个回答

1

我建议你(这也是最简单的方法)把这项工作交给一些第三方服务,然后在你的代码中调用他们的库。

MailChimp 看起来很受欢迎(这是他们的 API)。他们还提供了一个非常慷慨的免费计划。

SocketLabs 也是一个不错的选择(这是他们的 API)。你可以在谷歌上找到很多其他的选择。

6

最快的方式是在你的机器上安装一个邮件传输代理,比如Postfix,然后把所有的邮件交给它来发送,使用/usr/sbin/sendmail这个邮件接口。大多数合理的邮件服务器每秒可以处理成千上万封邮件,并且可能会进行一些SMTP管道处理,这样可以在一次连接中把邮件发送给同一个域的多个收件人,这样可以大大减少网络流量,提高邮件发送的效率。(这不会影响用户看到的邮件内容。)

大多数邮件服务器也能很好地处理临时宕机的服务器,这一点非常重要,因为许多网站使用灰名单来对抗垃圾邮件。

不过,如果你真的想在Python中通过网络连接联系SMTP服务器,使用一个线程池来发送邮件是个不错的主意。这个线程池会从队列中取出地址,创建并发送邮件,然后再回到队列中处理下一个地址。你现在的代码是为每封邮件都创建和销毁一个新线程。创建和销毁线程需要时间,这些时间本可以用来处理你的邮件。

此外,线程池还会限制活跃连接的总数。没有必要同时为一个邮件服务器创建1000个独立的连接。每次建立连接时需要进行三次握手,这个过程会消耗三倍的延迟时间才能建立TCP连接,然后才能发送任何SMTP流量。所以,创建十个线程并用这十个连接来发送邮件是个好主意。(其实十个可能有点多,两三个就可能更合适。甚至一个线程可能是最好的选择,不过如果这个连接断了(每个连接的邮件限制?),你就会有一段时间无法发送任何邮件,直到重新建立连接。)

你现在创建的情况很像雷鸣群体问题——你启动了数百或数千个线程,但可能没有足够的内存同时保持它们在RAM中运行。这样可能会导致频繁的内存交换,严重降低你的发送系统的性能,而单个线程执行时可能完全在内存中运行,不会因为交换而停顿。

撰写回答