You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 03:11:26