PHP、sendmail 和传输 - 如何加快邮件发送速度

Posted

技术标签:

【中文标题】PHP、sendmail 和传输 - 如何加快邮件发送速度【英文标题】:PHP, sendmail and transports - how to speed up mail sending 【发布时间】:2011-10-03 09:29:06 【问题描述】:

我刚刚编写了一组批量电子邮件类,用于处理大量电子邮件并根据传递的参数解析其内容。如果我从我的数据库中对 1000 个随机收件人和 1000 个随机发件人测试一封电子邮件,直到脚本到达 send() 部分(我现在评论它),我得到大约 2 秒的性能和 20 MB 的峰值内存,太好了。

但是,如果我取消注释发送部分,发送需要 30 秒。这是不可接受的,我想以某种方式加快速度。从测试中很明显,延迟是由 $mail->send() 调用引起的,好像它在继续循环并发送下一封电子邮件之前等待它返回一些东西。

我想知道的是:如何加快 send() 调用?我该怎么做才能让它更快?我尝试使用两种发送方式:

    Zend SMTP 传输,直接连接到服务器并发送。每 1000 封电子邮件需要 30 秒。 通过 Zend_Mail 发送邮件。在准备好每封电子邮件后,只需调用 Zend_Mail 的发送函数。这需要 60 秒。

请注意,排队绝对是一种选择,我已经将它内置到我的课程中。所需要的只是激活一个 cron,它就像一个魅力。但我想知道实际发送以及如何加快发送速度。所以,实际的 send() 调用。

【问题讨论】:

【参考方案1】:

您需要加快服务器上的 MTA。我推荐 Postfix,并且您确实阅读了每个设置,以便您知道如何对其进行微调。对于商业解决方案,我听说 PowerMTA 是一个不错的选择,但我自己从未尝试过。

你只能从一台机器上挤出这么多的性能,但是一旦你正确配置了一台常规的专用服务器,它应该能够传送相当数量的邮件。最大的性能瓶颈通常是存储邮件队列的磁盘驱动器,因此请考虑使用 SAS(10k 甚至 15k RPM)或 SSD 驱动器。

【讨论】:

我一定会调查的。我们的电子邮件输出很快就会显着增加,这样的提升可能是非常必要的。 我们已经开始计划这种方法,但我们也会将 Tomas 的回答纳入我们的解决方案。到目前为止,它实际上已被证明非常棒。【参考方案2】:

您可以尝试深入研究 php pcntl-fork 函数。因此,您可以在解析下一封电子邮件时将发送留在另一个进程中。

B计划

您可以将电子邮件对象序列化并保存到数据库队列中,并让另一个脚本在后台发送它们。这个脚本可以无限循环(while true)运行,每次迭代都有一些sleep。您甚至可以运行此脚本的多个实例,但请确保两个脚本不会同时开始发送同一封电子邮件。

为确保脚本仍在运行,您可以在 Unix 机器上使用 monit。如果旧实例由于某种原因失败,它可以启动脚本。

【讨论】:

嗯,这看起来很吸引人,但是如果 PHP 作为 Apache 模块运行,PCNTL 函数不可用吗?我似乎记得在某个地方读过一些关于那个的东西,但再也找不到这些信息了。此外,PCTNL 在 Windows 机器上不可用,我在各种操作系统上开发此应用程序,具体取决于我在特定时刻的位置.. 我已经在使用这种排队方式了。电子邮件数据被序列化并以给定的优先级保存到数据库中。然后,cronjob 通过每 15 分钟获取 500 封最高优先级的电子邮件来定期处理发送,这似乎一切都很好。但我真正想要的只是加速 send() 函数,而专用服务器可能只是唯一且最好的长期解决方案。【参考方案3】:

我会将邮件保存在一个目录中并使用 shell 脚本(cron/daemon/...)发送它们:

Zend_Mail::setDefaultTransport(
    new Zend_Mail_Transport_File(
        array(
            'path' => __DIR__,
            'callback' => function() 
                do 
                    $file = 'email-' . date('Y-m-d_H-i-s') . '_' . mt_rand() . '.eml';
                 while (file_exists($file));
                return $file;
            ,
        )
    )
);

【讨论】:

如果我错了,请纠正我,但是一个好的 mysql 查询总是会胜过文件读取。无论哪种方式,排队机制都已经完成,现在不需要改进。同样,我们的电子邮件每封都有不同的内容。因此,当我们在 2 秒内发送 1000 封电子邮件时,每封电子邮件都有不同的收件人、不同的发件人和不同的内容。我相信您在此处显示的这一方面仅可用于批量发送电子邮件,是吗?所有消息中的内容在哪里相同?如果没有,问题仍然存在——这会比在数据库中排队更快吗?我很怀疑。 我认为问题是发送而不是生成! :) 可能有一些经过优化的邮件服务器,可以批量加载大量邮件。无论如何 - 它会比 php 的 sendmail 方法更快。直接服务器访问应该比 php 要多很多倍(例如,它可以使用持久连接)。 嗯,完全正确。准备好的电子邮件可以轻松地以 eml 格式保存到磁盘,然后脚本将接管。这也可以作为一个备用队列体面地服务。您是否有任何以有效方式完成此操作的示例?我很想看看一些。 不,实际上不是。我使用上面的代码转储邮件而不是在开发机器上发送。我想你可以有一个 RAMDisk/SSD 来保存这些电子邮件,然后你唯一需要的就是找到一个能够以不错的速度从目录发送的服务器;) 但是对于极端的预先解决方案,我建议完全绕过 Zend 并自己转储电子邮件,因为您可能不需要一些测试、编码等,这会减慢电子邮件的创建速度。但现在这样做,将是过早的优化。 :)

以上是关于PHP、sendmail 和传输 - 如何加快邮件发送速度的主要内容,如果未能解决你的问题,请参考以下文章

php 使用sendmail发送邮件

如何使用 perl 和 sendmail 从 URL 发送 pdf [Mail::Sendmail]

unix 的 php.ini 中的 sendmail_path [电子邮件发件人的全名]

我配置了我的 sendmail.ini 和 php.ini 但我无法使用 php 中的 mail() 函数发送电子邮件

怎么利用php发送邮件求详细教程

PHP 直接通过sendmail从PHP发送多部分/替代(文本和html一起)电子邮件