队列发邮件需配置、驱动、监听器三者协同;缺一不可,否则邮件不发。QUEUE_CONNECTION必须设为database或redis,禁用sync;Mail::queue()立即入队,Mail::later()延迟入队;监听器须指定队列名并常驻运行。

队列发邮件不是加个 queue() 就完事——它依赖配置、驱动、监听器三者严丝合缝,缺一不可。本地开发时看着没报错,但邮件就是不发,八成卡在队列没启动或驱动配错了。
队列驱动必须显式启用,不能靠默认
默认的 QUEUE_CONNECTION=sync 是同步执行,queue() 看似调用了,实则立刻走完,根本没进队列。生产或测试异步行为,必须改用真实队列驱动:
-
QUEUE_CONNECTION=database:最轻量,只需运行php artisan queue:table+php artisan migrate -
QUEUE_CONNECTION=redis:性能更好,但需确保 Redis 服务可用且config/database.php中已正确定义redis连接 - 改完后务必执行
php artisan config:clear,否则.env变更不生效
Mail::queue() 和 Mail::later() 的实际差异
两者都绕过同步发送,但语义和底层处理不同:
-
Mail::to('a@b.com')->queue(new WelcomeEmail()):立即入队,由queue:work拉取执行 -
Mail::to('a@b.com')->later(now()->addMinutes(5), new WelcomeEmail()):延迟入队,时间精度取决于队列驱动(database驱动下最小延迟约 1 分钟) - 注意:
later()不支持sync驱动,会直接报错Call to undefined method later()
队列监听器必须常驻运行,且指定队列名
只写 queue() 不等于邮件就发了——它只是把任务塞进队列,没人消费就一直躺着:
- 启动监听器命令必须带
--queue参数,例如:php artisan queue:work --queue=emails - 如果 Mailable 类里写了
$this->onQueue('emails'),但监听器没指定对应队列名,任务永远不被执行 - 开发时建议加
--tries=3 --timeout=60避免失败任务卡死队列 - 用
supervisor或systemd管理进程,别靠手动开终端跑
调试时最容易忽略的三个断点
邮件进队列了但没发出来?先盯住这三个地方:
- 检查
failed_jobs表:有记录说明队列执行时报错,常见是 SMTP 凭证失效、视图路径不存在、Blade 模板语法错误 - 看日志:
storage/logs/laravel.log里搜Swift_TransportException或Connection could not be established - 确认 Mailable 的
build()方法没抛异常:比如$this->view('nonexistent')不会报错,但会导致空邮件静默失败
队列发邮件真正的难点不在代码怎么写,而在于环境链路是否完整——从 .env 配置、迁移表创建、监听器启动,到 SMTP 连通性验证,漏掉任意一环都会让邮件消失得毫无痕迹。


















