使用PHPMailer通过Gmail批量发邮件中途SMTP认证失败求助
解决Gmail SMTP批量发送邮件中途认证失败的问题
问题原因
这是Gmail的常见限制导致的,核心关键点包括:
- Gmail对SMTP连接复用次数、认证频率有严格的安全管控,批量发送时长期复用同一个连接,容易触发临时认证拦截
- 若账号开启了两步验证(2FA),用普通密码登录SMTP会直接失败,必须使用应用专用密码
- 短时间内发送频率过高,哪怕加了短间隔,也可能触发Google的反滥用机制
具体解决方案
1. 替换为应用专用密码(必做,若开启2FA)
如果你的Gmail账号开了两步验证,绝对不能用普通密码登录SMTP。去Google账号的「安全」设置里找到「应用专用密码」,生成一个专门用于SMTP的密码,替换代码里的$mail->Password值。
2. 调整连接复用策略,避免长期保持同一SMTP连接
Gmail不建议长时间复用SMTP连接,批量发送时可以每发送N封就重新初始化PHPMailer实例,关闭旧连接。修改后的代码示例:
$SQL="SELECT ID_NO, EMAIL FROM CUSTOMERS"; $qry = sqlsrv_query($conn, $SQL); $sendCount = 0; $batchSize = 20; // 每20封重新创建一次连接 while($row = sqlsrv_fetch_array($qry, SQLSRV_FETCH_BOTH)) { // 达到批次数量,重新初始化PHPMailer if ($sendCount % $batchSize === 0) { if (isset($mail)) { $mail->smtpClose(); // 关闭旧连接 unset($mail); } $mail = new PHPMailer(true); $mail->isSMTP(); $mail->SMTPDebug = 0; $mail->SMTPAuth = true; $mail->isHTML(true); $mail->Host = 'smtp.gmail.com'; $mail->Username = 'xxxx@gmail.com'; $mail->Password = '你的应用专用密码'; // 替换为生成的应用密码 $mail->Port = 465; $mail->SMTPSecure = 'ssl'; $mail->setFrom('xxxx@gmail.com', ''); } $mail->ClearAddresses(); $mail->addAddress($row['EMAIL'], ''); $mail->Subject = 'xxxx'; $mail->Body = 'xxxx'; try { $mail->send(); } catch (Exception $e) { // 记录失败日志,方便后续排查 error_log("邮件发送失败至 {$row['EMAIL']}: " . $e->getMessage()); // 失败后重试一次,间隔5秒 sleep(5); try { $mail->send(); } catch (Exception $retryErr) { error_log("重试后仍失败至 {$row['EMAIL']}: " . $retryErr->getMessage()); } } $sendCount++; sleep(1); // 延长发送间隔到1秒,降低触发频率限制的概率 } // 循环结束后关闭最后一个连接 if (isset($mail)) { $mail->smtpClose(); }
3. 优化发送频率和批次
- 把原代码中的
usleep(200000)(仅0.2秒间隔)改成sleep(1)或sleep(2),给足够间隔避免触发频率限制 - 可以分大批次发送,比如每发送50封就暂停5分钟,再继续下一批
4. 检查账号安全状态
登录你的Gmail账号,查看「安全」页面的通知,确认是否有SMTP登录被标记为异常的提示,若有,手动允许该登录来源即可。
补充说明
这种中途认证失败是Gmail为防止邮件滥用设置的常规限制,批量发送时必须严格遵守其SMTP使用规范,否则很容易触发临时的认证拦截甚至账号限制。
内容的提问来源于stack exchange,提问作者Glenn
相关产品推荐
相关产品推荐

