Laravel邮件发送需正确配置MAIL_MAILER及对应驱动参数,清除配置缓存后用Mail::raw()验证SMTP连通性;附件应使用attachFromStorage()配相对路径;队列发送须设置QUEUE_CONNECTION并监听;测试时Mail::fake()会屏蔽真实发送,上线前必须实测。

Laravel 的 Mail 类本身不负责实际发信,它只是个门面(Facade),真正干活的是底层的邮件驱动(如 smtp、mailgun、log)。能发出去的前提,是驱动配置正确且网络可达。
确认 MAIL_MAILER 和对应驱动配置是否生效
Laravel 从 7.x 起默认使用 MAIL_MAILER 环境变量决定驱动,而非旧版的 MAIL_DRIVER。如果 .env 里还写着 MAIL_DRIVER=smtp,但没设 MAIL_MAILER,Laravel 会静默 fallback 到 log 驱动 —— 邮件根本不会发出,控制台也无报错。
-
MAIL_MAILER=smtp是必须显式设置的,哪怕你用的是 Mailgun 或 SES - SMTP 场景下,
MAIL_HOST、MAIL_PORT、MAIL_USERNAME、MAIL_PASSWORD缺一不可;端口注意:587(TLS)和 465(SSL)行为不同,Laravel 默认用 TLS,若服务要求 SSL,得额外配MAIL_ENCRYPTION=ssl - 改完 .env 后务必运行
php artisan config:clear,否则缓存会掩盖配置问题
用 Mail::raw() 快速验证基础通路是否畅通
绕过 Mailable 类、视图渲染等环节,直连 SMTP 发纯文本,能最快定位是配置问题还是业务逻辑问题。
use Illuminate\Support\Facades\Mail;
Mail::raw('Hello from Laravel!', function ($message) {
$message->to('test@example.com')
->subject('Laravel SMTP Test');
});
如果这步失败,错误信息通常明确指向连接拒绝、认证失败或证书问题;如果成功,说明 SMTP 配置没问题,后续可放心构建 Mailable。
Mailable 类中 attachFromStorage() 与相对路径陷阱
想在邮件里附带存储在 storage/app 下的 PDF 报表?别直接传 storage_path('app/reports/2024.pdf') 给 attach() —— 它只接受绝对路径,且该路径需对 PHP 进程可读。更安全的做法是用 attachFromStorage(),但要注意它默认基于 local 磁盘,且路径是「磁盘内路径」,不含 storage/app/ 前缀:
- 文件实际存在
storage/app/reports/2024.pdf→attachFromStorage('reports/2024.pdf')✔️ - 写成
attachFromStorage('storage/app/reports/2024.pdf')❌(找不到) - 若用的是
s3磁盘,attachFromStorage()仍可工作,但需确保 S3 凭据有效且文件可公开读(或生成预签名 URL)
队列发送时忘了设置 QUEUE_CONNECTION 导致阻塞
用 Mail::to(...)->queue(new WelcomeMail()) 时,如果 QUEUE_CONNECTION 仍为默认的 sync,邮件会同步执行 —— 表面上“发成功了”,但用户请求会被 SMTP 延迟拖住。更隐蔽的问题是:若你本地没跑 Redis 或数据库队列监听器,而误以为已启用异步,邮件就卡在 jobs 表或 Redis 里不动。
- 开发环境快速验证队列:设
QUEUE_CONNECTION=database,运行php artisan queue:work --once - 生产环境务必用
redis或supervisor持续监听,不能依赖php artisan queue:work手动触发 -
Mail::fake()在测试中很好用,但它会吞掉所有发送行为 —— 单测通过不代表线上能发,上线前必须关掉 fake 并真机测一次
邮件发送链条长,任意一环(DNS 解析、防火墙、SMTP 限频、邮箱服务商拒收)都可能让信消失无声。最稳妥的方式是:先用 Mail::raw() 过基础,再用队列发真实 Mailable,最后查收件箱或 SMTP 日志,别只看 Laravel 日志里有没有 “Message sent”。










