邮件发不出去主因是配置未生效、收件人未指定或使用账号密码而非应用专用密码:mail_mailer未设导致退化为log/array驱动,to()调用缺失或位置错误,gmail/qq/163等必须用应用专用密码而非登录密码。

邮件发不出去,八成不是代码写错了,而是配置没生效或收件人没指定——MAIL_MAILER 没设、to() 漏调、Gmail 用的还是账号密码,这三类问题占了 Laravel 邮件失败的 90% 以上。
MAIL_MAILER 必须显式设置,不能依赖默认值
Laravel 不会自动 fallback 到 smtp;如果 .env 里没写 MAIL_MAILER=smtp,它可能走 log(开发时静默写日志)或直接报错。尤其在 CI/CD 或线上环境,缓存没清、.env 权限不对、变量被注释掉,都会让这个值变成 null。
- 执行
php artisan tinker后输入config('mail.default'),确认返回的是你期望的驱动名(如"smtp"),不是null或"array" -
MAIL_MAILER必须是smtp、mailgun、log等合法值,拼错(比如写成smpt)不会报错,但会静默退化为array驱动——发不出去,也不提示 - 改完
.env后必须运行php artisan config:clear,否则旧缓存还在,config('mail')看到的还是错的
to() 是硬性前置条件,不能省略也不能晚于 send()
调用 Mail::send(new WelcomeEmail) 或漏掉 ->to(...) 链式调用,会抛出 Symfony\Component\Mailer\Exception\TransportException: No recipients specified。这不是警告,是直接中断。
- 收件人必须是字符串(
"user@example.com")或数组(["a@x.com", "b@x.com"]),不能传User::first()实例,哪怕它有email属性 - 批量发送别写
foreach ($users as $u) { Mail::to($u->email)->send(new OrderShipped()); },性能差还容易触发频率限制;改用Mail::to($users)->send(new OrderShipped()),Laravel 自动展开 - 如果要用队列,
->to()必须在->queue()前完成,例如Mail::to($user)->queue(new WelcomeEmail);在队列任务内部再调to()会找不到上下文,报Call to undefined method ...to()
Gmail/163/qq 邮箱必须用应用专用密码,不是登录密码
2025 年起,Gmail、QQ、163 等主流邮箱已全面禁用“账户密码 + SMTP”直连方式。用登录密码只会返回 Expected response code 235 but got code "535" 或超时无响应。
- Gmail:进 Google 账户 → 安全性 → 两步验证(先开)→ 应用专用密码 → 选“邮件”+“其他”,生成 16 位密码,填入
MAIL_PASSWORD - QQ 邮箱:设置 → 账户 → POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服务 → 开启 SMTP 服务 → 获取授权码(不是 QQ 密码!)
- 163/126:设置 → POP3/SMTP/IMAP → 开启 SMTP → 客户端授权码 → 记下该密码,
MAIL_PORT和MAIL_ENCRYPTION要匹配(465 + ssl,或 587 + tls)
附件中文名必须用 attachData(),不能直接 attach()
attach('/path/to/简历.pdf') 在 Linux 服务器上大概率失败,因为路径含中文或文件名含中文时,底层 fopen 打不开;更隐蔽的问题是,即使打开成功,收件人看到的附件名也是乱码或空。
- 正确做法:读取文件内容后用
attachData()显式指定filename,例如:$this->attachData(file_get_contents($path), '张三-简历.pdf', ['mime' => 'application/pdf']) -
attach()只接受绝对路径,相对路径(如storage/app/file.pdf)会报File not found;务必用storage_path('app/file.pdf')拼出绝对路径 - 大附件(>5MB)建议走对象存储+链接,别硬塞进邮件;SMTP 服务普遍有单封 25MB 限制,且容易被当垃圾邮件拦截
最常被跳过的其实是日志验证环节:开发时先把 MAIL_MAILER=log,发一封,然后看 storage/logs/laravel.log 里有没有完整邮件头和 HTML 内容——有,说明 Mailable 和视图没问题;没有,问题一定出在配置或调用链前端。别一上来就配 Gmail,先让 log 驱动跑通。











