Symfony发邮件依赖Mailer组件,需严格配置MAILER_DSN(如Gmail必须含?auth_mode=login),模板路径须以templates/开头且用context()传参,禁用spool和异步队列可避免静默失败,多传输通过X-Transport头灵活切换。

Symfony 发邮件靠的是 Mailer 组件,不是老的 Swiftmailer(已废弃)。配置对了才能发,配错一个字符——比如少个 ?auth_mode=login 或写错端口——它就静默失败:不报错、不提示、邮件根本没出去。
DSN 配置是关键,格式不能错
Mailer 用 MAILER_DSN 环境变量控制传输方式,格式必须严格:
-
smtp://user:pass@smtp.gmail.com:587?encryption=tls&auth_mode=login(Gmail 必须带auth_mode=login) -
sendmail://default(本地开发推荐,无认证烦恼) -
smtp://localhost:1025(配合 MailHog 查看邮件内容,不真发) - 别写成
smtps://却不配encryption=ssl;也别漏掉&把参数连在一起
模板邮件要按规则写路径和传参
用 TemplatedEmail 发 HTML 邮件时,两处容易踩坑:
- 模板路径必须以
templates/开头,例如:templates/email/welcome.html.twig,调用时只写'email/welcome.html.twig' - 变量必须用
->context(['user' => $user]),不是->with();否则模板里取不到值 - 如果启用了
inline_css: true,得装两个包:symfony/css-selector和tijsverkoyen/css-to-inline-styles,否则自动退化为纯文本
发不出?先查是不是被异步或 spool 拦住了
默认是同步发送,但如果你开了 Messenger 异步队列:
- 邮件会被扔进
messenger.transport.async,但你不跑php bin/console messenger:consume,它就卡在数据库里不动 - 开发阶段建议在
config/packages/mailer.yaml显式指定传输:transport: 'smtp',别留null或async - Symfony 6.2+ 已移除
spool,若配置里还留着spool: { type: memory },Mailer 会悄悄 fallback 到null://—— 一封都发不出
多 SMTP 场景下怎么灵活切换
不同邮件走不同通道(比如通知走 Gmail,重要告警走 SendGrid),可配多个传输:
- 在
config/packages/mailer.yaml里定义:transports:<br> main: '%env(MAILER_DSN_MAIN)%'<br> important: '%env(MAILER_DSN_IMPORTANT)%'
- .env 中对应写:
MAILER_DSN_MAIN=smtp://...<br>MAILER_DSN_IMPORTANT=sendgrid://KEY@default
- 发重要邮件时,在 Email 对象里加头:
$email->getHeaders()->addTextHeader('X-Transport', 'important');
Mailer 会自动识别并切换传输,且这个头不会出现在发出的邮件中


















