使用PHPMailer与内部邮件中继批量发送4500封邮件延迟优化求助
PHPMailer批量发送邮件提速方案探索
问题概述
已配置PHPMailer且运行正常,核心逻辑为拆分邮箱列表变量,循环触发单封邮件发送。当前发送约4500封邮件耗时12分钟,希望探索提速方案。代码部署在自有服务器,使用公司内部邮件中继服务器,无任何限流措施,想了解是否支持多并发发送。
发送耗时日志示例
Tue Nov 28 16:49:29.074897 Tue Nov 28 16:49:29.357597 0.28 seconds to send Tue Nov 28 16:49:29.366940 Tue Nov 28 16:49:29.500178 0.14 seconds to send Tue Nov 28 16:49:29.510758 Tue Nov 28 16:49:29.635567 0.12 seconds to send Tue Nov 28 16:49:29.645406 Tue Nov 28 16:49:29.776114 0.13 seconds to send Tue Nov 28 16:58:28.549093 Tue Nov 28 16:58:28.907755 0.36 seconds to send Tue Nov 28 16:58:28.917883 Tue Nov 28 16:58:29.041314 0.13 seconds to send Tue Nov 28 16:58:29.051385 Tue Nov 28 16:58:29.322760 0.27 seconds to send
注:第一个时间戳为邮件中继欢迎消息的服务器到客户端日志,最后一个为服务器到客户端的Bye消息。
日志细节疑问
- HTML内容首条时间戳16:58:27.144792,末条16:58:27.167857,不确定此耗时是否正常;
SERVER -> CLIENT: 220 2.0.0 Ready to start TLS\r\n与下一行CLIENT -> SERVER: EHLO间隔0.06秒,不确定是否正常;- 内容发送至邮件中继后,间隔0.06秒才收到“OK Queued”确认,不确定是否应更即时。
核心发送代码
$mail->Body = $body; $mail->IsHTML(true); $addresses = explode(',', $customerlist); foreach ($addresses as $address) { $mail->ClearAllRecipients(); $mail->addBCC($address); if (!$mail->send()) { $emailoutput .= "Mail <font color=red><b>Not</font></b> Sent to $address - <b>Error:</b> $mail->ErrorInfo<br>"; } else { $emailoutput .= "Mail <font color=green><b>Successfully</font></b> Sent to $address<br>"; } }
优化建议
1. 复用SMTP连接(最有效)
当前代码每次循环都重建SMTP连接(从日志里的欢迎消息和Bye消息可确认),这是最大耗时点。PHPMailer支持保持SMTP连接,只需在循环外初始化连接,循环内不关闭:
$mail->Body = $body; $mail->IsHTML(true); // 提前建立一次SMTP连接 if (!$mail->smtpConnect()) { die('SMTP连接失败: ' . $mail->ErrorInfo); } $addresses = explode(',', $customerlist); foreach ($addresses as $address) { $mail->ClearAllRecipients(); $mail->addBCC($address); if (!$mail->send()) { $emailoutput .= "Mail <font color=red><b>Not</font></b> Sent to $address - <b>Error:</b> $mail->ErrorInfo<br>"; } else { $emailoutput .= "Mail <font color=green><b>Successfully</font></b> Sent to $address<br>"; } } // 循环结束后统一关闭连接 $mail->smtpClose();
此操作可避免重复TLS握手、EHLO等步骤,按日志数据估算,4500次发送至少能节省270秒(4.5分钟)。
2. 批量添加收件人(内容无个性化时首选)
如果邮件内容完全一致,无需个性化处理,可直接将所有BCC地址一次性添加,仅发送一次:
$mail->Body = $body; $mail->IsHTML(true); $addresses = explode(',', $customerlist); foreach ($addresses as $address) { $mail->addBCC($address); } if (!$mail->send()) { $emailoutput .= "批量发送失败 - <b>Error:</b> $mail->ErrorInfo<br>"; } else { $emailoutput .= "所有邮件已成功批量发送<br>"; }
这种方式仅需一次SMTP交互,耗时会大幅降低,内部中继服务器通常无收件人数量限制,可放心使用。
3. 多并发发送(可行但需控量)
可通过PHP多进程(如pcntl_fork)、多线程扩展,或队列系统(Redis队列+多Worker进程)实现并发发送,但需注意:
- 控制并发数量,建议从4-8个进程开始测试,避免给内部中继服务器造成过大压力;
- 做好并发场景下的日志和错误记录,避免数据冲突;
- 若使用队列,需确保Worker进程的异常重启机制正常。
4. 日志细节说明
从日志数据看,HTML内容发送耗时0.023秒、TLS握手到EHLO间隔0.06秒、收到确认间隔0.06秒,均属于正常网络交互范围,无需针对这部分优化。
内容的提问来源于stack exchange,提问作者StevenLR
相关产品推荐
相关产品推荐

