symfony邮件传输配置核心是dsn,格式为scheme://user:pass@host:port?opt=val;配错即静默失败,须严格校验gmail的auth_mode=login、端口与encryption匹配,并优先通过.env中mailer_dsn设置,多传输需在mailer.yaml定义并用x-transport头指定。

Symfony 邮件传输配置核心是 DSN(Data Source Name),它决定了邮件通过什么方式、用什么凭证、连哪个服务器发出去。配错一个字符,邮件就静默失败——不报错、不提示、也不发,这是最常踩的坑。
DSN 格式必须严格正确
DSN 是 Symfony Mailer 的“连接字符串”,格式统一为:
scheme://user:password@host:port?option1=value1&option2=value2
常见错误和对应写法:
- Gmail 必须加 ?auth_mode=login,否则认证失败(哪怕用了 App Password);端口 587 要配 &encryption=tls,465 则用 &encryption=ssl
- 不要把 smtp:// 写成 smtps://(后者不是标准协议,Mailer 会忽略)
- 本地开发推荐用 sendmail://default 或 smtp://localhost:1025(配合 MailHog 查看邮件)
- 环境变量中定义时,确保没有空格或换行,比如:
MAILER_DSN=smtp://myuser:mypass@smtp.gmail.com:587?encryption=tls&auth_mode=login
配置位置与优先级
Symfony 读取传输配置有明确顺序,高优先级覆盖低优先级:
- 第一步:检查 .env 中的 MAILER_DSN —— 这是最常用、最推荐的方式
- 第二步:若没设 MAILER_DSN,则 fallback 到 config/packages/mailer.yaml 中的 framework.mailer.dsn
- 第三步:如果两者都没配,Mailer 会自动使用 null:// —— 邮件“发送成功”,但实际没走任何通道
验证是否生效?运行:
bin/console debug:config mailer
看输出里 transports 下是不是你写的 DSN,而不是 null 或空值。
多传输场景怎么配
一个项目要发通知、营销、告警三类邮件?别硬塞进一个 SMTP。用命名传输更灵活:
- 在 config/packages/mailer.yaml 中定义多个传输:
framework:
mailer:
transports:
notify: '%env(MAILER_DSN_NOTIFY)%'
marketing: '%env(MAILER_DSN_MARKETING)%'
- 发邮件时指定传输:
$email->getHeaders()->addTextHeader('X-Transport', 'marketing'); - 注意:transports 下第一个(如 notify)是默认传输,不加头就走它
常见静默失败排查点
邮件没收到,但控制台没报错?重点查这几项:
- 是否启用了异步队列?framework.messenger.transport.async 开了,就得手动运行 php bin/console messenger:consume,否则邮件卡在数据库里
- 是否残留旧版 spool 配置?Symfony 6.2+ 已移除 spool,还留着 spool: { type: memory } 会导致直接 fallback 到 null
- 是否设置了 fail_silently=true?应改为 false,让异常浮出水面
- 模板路径写错?TemplatedEmail::htmlTemplate() 只认 templates/xxx.html.twig,不能写绝对路径或 src/ 开头











