核心是确保SMTP驱动连通且本地开发用log驱动调试:必须在.env配置MAIL_MAILER=smtp及匹配的HOST/PORT/PASSWORD/ENCRYPTION,改后运行php artisan config:clear;本地开发设MAIL_MAILER=log可绕过网络直接查日志验证逻辑。

配置 Laravel 邮件发送,核心是让 SMTP 驱动真正连上发信通道,同时在本地开发阶段避免真实发信、快速验证逻辑是否走通。关键不在于改多少文件,而在于环境变量写对、缓存清掉、驱动行为看准。
SMTP 配置只认 .env,别碰 config/mail.php
Laravel 启动时会把 .env 里的 MAIL_* 变量注入到配置中,config/mail.php 是模板,不是运行时配置源。改了它却没生效?大概率是误操作。
- 必须写进 .env 的最小集合:
MAIL_MAILER=smtp
MAIL_HOST=smtp.qq.com(QQ邮箱)或 smtp.gmail.com(Gmail)或 smtp.office365.com(Outlook)
MAIL_PORT=587(配 tls)或 465(配 ssl)
MAIL_USERNAME=your_email@qq.com
MAIL_PASSWORD=16位授权码(不是登录密码!QQ/Gmail/Outlook 均需开启 SMTP 并生成专用密码)
MAIL_ENCRYPTION=tls 或 ssl(必须与端口严格匹配) - 改完立刻执行:
php artisan config:clear,否则新配置不加载 - 验证是否读取成功:进
php artisan tinker,输入env('MAIL_MAILER')和env('MAIL_HOST')看输出
本地开发首选 MAIL_MAILER=log,跳过网络依赖
不想配 SMTP、不希望邮件真发出去、只想确认「代码调用了发送逻辑」——用 log 驱动最稳。
- 只需在 .env 中设:MAIL_MAILER=log
- 发一封测试邮件后,打开
storage/logs/laravel.log,搜索Subject:或to:,能看到完整邮件头和纯文本内容 - 这个方式完全绕过网络、认证、防火墙、openssl 扩展等问题,适合快速验证业务流程是否走到发信环节
- 确认逻辑无误后,再切回 smtp 驱动,避免把环境问题和业务问题混在一起排查
Mailtrap 测试要避开三个静默失败点
Mailtrap 是本地 SMTP 沙盒的常用选择,但它不是“填完就通”。很多失败没有报错,只是邮件根本没发出去。
-
端口与加密必须匹配:用 PORT=2525 就设 MAIL_ENCRYPTION=null;用 PORT=587 就必须设 MAIL_ENCRYPTION=tls。填错一个,
Mail::send()就静默失败 -
队列必须关掉:默认情况下
Mail::to()->send(new WelcomeMail)可能被塞进队列。本地没跑queue:work,等于没发。临时解决:在 .env 加 QUEUE_CONNECTION=sync,或改用Mail::send()(非 queue) -
别用裸 view() 渲染邮件:直接
Mail::send('emails.welcome', [...], function() {...})容易导致样式丢失、asset 路径失效。应使用 Mailable 类封装,并在类里调$this->view('emails.welcome'),它会自动内联 CSS、处理相对路径
发不出邮件?先盯住日志和底层异常
浏览器白屏、tinker 卡住、没报错但没收到信——别猜,直接查证据。
- 打开
storage/logs/laravel.log,搜关键词:Swift_TransportException、Connection could not be established、535 Authentication failed - 常见错误含义:
535 错误 → 用户名或密码错,重点核对是不是用了授权码
Connection timed out → 服务器屏蔽了端口(如阿里云/腾讯云默认封 587),换 465+ssl 试试
STARTTLS command first → MAIL_ENCRYPTION 没设或设错,比如该写 tls 却留空 - 加一句调试代码:
dd(\Illuminate\Support\Facades\Mail::failures());放在Mail::send()后,看是否返回空数组(成功)还是含邮箱地址(失败)



















