
phpmailer 在循环发送邮件时,若未重置收件人列表,会导致所有历史地址累积,使每位收件人收到发给其他人的邮件。解决方案是在每次发送后调用 `clearaddresses()` 或 `clearallrecipients()` 清除收件人缓存。
在使用 PHPMailer 批量发送个性化邮件(如通知、账单或订阅内容)时,一个常见却极易被忽视的错误是:未在每次循环迭代后清空收件人地址。PHPMailer 的 addAddress() 方法并不会覆盖已有收件人,而是持续追加——这意味着第一次循环添加了 user1@example.com,第二次循环会变成 [user1@example.com, user2@example.com],第三次则继续累加……最终每位收件人都会收到发给所有人的邮件,严重破坏隐私与准确性。
正确的做法是在每次成功调用 $mail->send() 后,立即清除当前邮件对象中的收件人信息。若仅使用 To 字段,调用 $mail->clearAddresses() 即可;若同时使用了 CC 或 BCC,则必须使用更彻底的 $mail->clearAllRecipients(),以确保下一轮发送完全“从零开始”。
以下是修正后的完整示例代码:
foreach ($id as $mailId) {
// 查询用户数据
$connect->connect('account WHERE id = :id', array('id' => $mailId), '', 0);
$users = $connect->connect->fetch(PDO::FETCH_ASSOC);
$name = $users['name'] ?? '用户';
$mailAdres = $users['mail'] ?? '';
// 构建个性化内容(可扩展为 HTML 模板)
$mail_template = "亲爱的 {$name}:
这是一封专属您的邮件。
立即学习“PHP免费学习笔记(深入)”;
";
// 设置收件人(每次都是全新添加)
$mail->addAddress($mailAdres, $name);
// 配置邮件基础属性(建议移出循环以提升性能,此处为清晰演示保留)
$mail->isHTML(true);
$mail->CharSet = 'UTF-8';
$mail->Subject = $odemeType ?: '系统通知';
$mail->Body = $mail_template;
$mail->AltBody = strip_tags($mail_template); // 纯文本备用内容
try {
$mail->send();
echo "✅ 邮件已发送至 {$mailAdres}\n";
} catch (Exception $e) {
echo "❌ 发送失败({$mailAdres}):{$mail->ErrorInfo}\n";
}
// ✅ 关键步骤:清除本次收件人,避免累积
$mail->clearAllRecipients(); // 推荐 —— 兼容 To/CC/BCC 场景
}⚠️ 重要注意事项:
- clearAddresses() 仅清除 To 地址;clearCCs() 和 clearBCCs() 需单独调用。为防遗漏,强烈推荐统一使用 clearAllRecipients()。
- 不要在循环外初始化 $mail 实例前重复设置 isHTML()、CharSet 等全局配置——它们只需设置一次,放在循环外更高效。
- 建议为每封邮件添加 try...catch,避免单个失败阻断整个批量流程,并记录具体错误便于排查。
- 若需更高性能(如千级用户),应考虑队列系统(如 Redis + Worker)或使用 SMTP 批处理扩展,而非同步逐封发送。
遵循以上实践,即可确保每位收件人只收到属于自己的那封邮件,兼顾安全性、准确性和可维护性。











