Laravel 8队列发邮件执行失败 进入失败队列报两类错误求解决
问题记录
- 服务使用supervisor管理Laravel队列进程处理邮件发送,上线初期所有邮件写入
jobs表后均可被正常消费投递 - 异常出现后无通知邮件送达,当前
jobs表为空,所有发送失败的任务全部落入failed_jobs表 - 任务执行过程中固定抛出两类错误:
第一类错误:
第二类错误:ErrorException: fwrite(): SSL operation failed with code 1. OpenSSL Error messages: error:1420C0CF:SSL routines:ssl_write_internal:protocol is shutdown in /var/www/html/admin/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/StreamBuffer.php:223Swift_TransportException: Expected response code 250 but got an empty response in /var/www/html/admin/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/AbstractSmtpTransport.php:447 - 当前已完成配置:
- 使用Google Workspace(原GApps)邮箱,已在对应账号开启低安全应用访问权限
- supervisor worker配置如下:
[program:offerletter] process_name=%(program_name)s_%(process_num)02d command=php /var/www/html/admin/artisan queue:work database --sleep=3 --tries=3 --daemon autostart=true autorestart=true user=root numprocs=10 redirect_stderr=true stdout_logfile=/var/www/html/admin/offerletter.log stopwaitsecs=3600 - .env文件中SMTP配置如下:
MAIL_MAILER=smtp MAIL_HOST=smtp.googlemail.com MAIL_PORT=587 MAIL_USERNAME=### MAIL_PASSWORD=### MAIL_ENCRYPTION=tls MAIL_FROM_ADDRESS=### MAIL_FROM_NAME="${APP_NAME}" - 完成上述配置后问题仍未解决,需可落地的排查思路与解决方案。
排查思路与解决方案
1. 修正Google账号侧配置
- Google已于2022年5月全面下线个人账号、Workspace账号的「低安全性应用访问」能力,即使后台显示开关为开启状态,该规则实际已不生效,不可依赖该配置实现SMTP发信
- 先在Google Workspace管理员后台开启域内「允许应用访问账号」的相关权限,再对发信账号开启两步验证,生成16位应用专用密码,使用该密码替换.env中
MAIL_PASSWORD的原有值,禁止使用账号原登录密码作为SMTP认证密码 - 登录发信账号的Gmail网页端,检查是否存在安全告警、发信频率超限被临时封禁SMTP权限、发信行为被判定为垃圾邮件的通知,如有需先解除账号限制。
2. 修正SMTP配置并重载生效
- 将
MAIL_HOST配置项从smtp.googlemail.com替换为官方标准SMTP地址smtp.gmail.com,旧域名部分节点存在SSL证书异常、连接握手不稳定的问题 - 配置修改完成后,先执行
php artisan config:cache清除框架配置缓存,必须重启所有supervisor管理的队列进程:daemon模式下的队列进程会常驻内存,启动时已加载旧配置,不重启永远不会读取新的配置内容,重启命令为supervisorctl restart offerletter:*。
3. 修复队列长驻场景下的SMTP连接复用问题
- 当前配置10个并发队列进程处理任务,SwiftMailer默认会复用SMTP长连接,进程长时间运行时,闲置连接会被Gmail侧主动断开,进程持有已失效的连接发信就会触发SSL关闭、空响应的错误
- 调整队列启动参数,增加
--timeout=120配置,限制单任务最长执行时间为120秒,避免进程长时间挂起持有无效连接 - 适当下调并发进程数:SMTP发信属于IO密集型任务,10个并发很容易触发Gmail的发信频率限制,先将
numprocs调整为2,验证功能正常后再按需逐步上调 - 在邮件发送逻辑中增加连接重置逻辑,每次发信前主动断开旧连接重建,从代码层面规避长连接失效问题:
// 发信前主动重置SMTP连接 Mail::getSwiftMailer()->getTransport()->stop(); // 原有发信逻辑 Mail::to($target)->send(new NotificationMail());
4. 服务器网络与环境排查
- 在服务器命令行手动测试SMTP连通性:执行
telnet smtp.gmail.com 587,确认能正常收到SMTP服务端的欢迎响应,不存在服务器防火墙、安全组拦截出口587端口的问题 - 检查服务器出口IP是否被Gmail列入垃圾邮件黑名单,若IP近期存在批量发信、发送垃圾内容的记录,会被Gmail主动断开连接返回空响应
- 更新服务器系统的OpenSSL、ca-certificates组件到最新版本,执行
update-ca-certificates更新系统根证书库,避免证书校验失败导致SSL连接异常。
5. 验证步骤
- 上述所有调整完成后,执行
php artisan queue:restart触发所有队列worker平滑重启,再执行php artisan queue:retry all将failed_jobs表中的失败任务重新推入队列消费,验证邮件是否可以正常送达。
内容的提问来源于stack exchange,提问作者Hanis Harun
相关产品推荐
相关产品推荐

