
laravel 中使用定时任务 daily() 发送邮件却收不到,往往是因为 mailable 类启用了 queueable 特性但未运行队列监听器;本文详解如何排查、修复并选择同步/异步发送策略。
在 Laravel 中通过 Artisan 命令 + Scheduler 实现每日邮件推送是常见需求,但如你所遇——代码逻辑看似完整却始终收不到邮件,核心原因极大概率在于 队列机制未激活。
你的 NotifyEmail 类使用了 use Queueable, SerializesModels;,这意味着每次调用 Mail::to()->send() 时,Laravel 并不会立即发送邮件,而是将发送任务推入队列(如 database、redis 或 sync 驱动),等待队列工作者(queue worker)消费执行。若未启动 php artisan queue:work 或未配置 Supervisor 持续守护进程,这些任务将永久“挂起”,邮件永远不会发出。
✅ 快速验证与修复方案:
方案一:临时禁用队列(适合开发/调试)
修改 NotifyEmail 类,移除 Queueable 特性,并确保不调用 onQueue():
// app/Mail/NotifyEmail.php
details = $data;
}
public function build()
{
return $this->view('mail', ['details' => $this->details]);
// 注意:compact('details') 更简洁,无需 compact(varname: 'details') —— 后者语法错误
}
}同时,在命令中确保使用同步发送(默认行为已满足):
// 在 Notify.php 的 handle() 方法中无需改动,但可显式指定: Mail::to($email)->send(new NotifyEmail($data)); // ✅ 同步执行(无 Queueable 时)
方案二:正确启用队列(推荐生产环境)
保留 Queueable,但必须启动队列监听器:
- 确保 .env 中队列驱动配置正确(例如 QUEUE_CONNECTION=database 或 redis);
- 运行迁移创建队列表(如使用 database 驱动):
php artisan queue:table php artisan migrate
- 启动队列工作者(开发环境):
php artisan queue:work --tries=3 --timeout=60
- 生产环境请务必使用 Supervisor 等进程管理工具守护 queue:work,避免中断。
⚠️ 其他关键检查点:
- ✅ 邮箱配置:确认 .env 中 MAIL_MAILER, MAIL_HOST, MAIL_PORT, MAIL_USERNAME, MAIL_PASSWORD 等已正确设置,并执行 php artisan config:clear;
- ✅ 视图路径:确保 resources/views/mail.blade.php 存在且语法正确(如 {{ $details['title'] }} 要求 $details 是数组,若改用对象属性需调整为 {{ $details->title }});
- ✅ 日志调试:在 handle() 中添加日志,确认命令是否真正触发:
\Log::info('Daily notify command started. Total emails: ' . count($emails));
? 总结建议:
- 开发阶段优先采用同步发送(移除 Queueable),快速验证邮件逻辑与 SMTP 配置;
- 生产环境高并发场景下,务必启用队列 + 持久化守护,避免请求阻塞与超时;
- 永远不要在循环中频繁调用 Mail::send()(尤其配合队列时易压垮 Redis/DB),可考虑批量投递或使用通知渠道聚合优化。
至此,你的每日邮件定时任务将稳定、可靠地送达每一位用户。










