notifier.yaml 中 transport 必须显式配置,空 transports 时 send() 直接跳过;需按 chatter_transports/texter_transports/mailer_transports 分类声明,DSN 环境变量命名和格式须严格匹配文档,Notification::getChannels() 应动态返回渠道,开发环境推荐用 null:// 并通过 notifier:transport:debug 命令验证配置。

notifier.yaml 里 transport 配置必须显式声明
Notifier 不会自动启用任何渠道,transports 字段为空时,send() 调用直接跳过,不报错也不发。常见错误是只装了 symfony/twilio-notifier 却没在配置里写 sms: 'twilio://...'。
正确做法是:在 config/packages/notifier.yaml 中明确列出所有要用的 transport:
notifier:
chatter_transports:
slack: '%env(SLACK_DSN)%'
texter_transports:
sms: '%env(TWILIO_DSN)%'
mailer_transports:
email: '%env(MAILER_DSN)%'
注意三点:
-
chatter_transports对应 Slack、Telegram 等聊天类渠道 -
texter_transports对应短信类(sms是固定键名,不能写成twilio) -
mailer_transports对应邮件,且需已安装symfony/mailer
环境变量 DSN 必须严格匹配文档命名
DSN 解析失败时 Notifier 默认静默,连 warning 日志都不打。问题往往出在环境变量名拼写或格式上。
例如 Twilio 的 DSN 要求四个变量全齐:
-
TWILIO_ACCOUNT_SID(不是TWILIO_SID) -
TWILIO_AUTH_TOKEN(不是TWILIO_TOKEN) -
TWILIO_FROM(值必须是 Twilio 控制台验证过的号码,带+) -
TWILIO_DSN格式为twilio://$TWILIO_ACCOUNT_SID:$TWILIO_AUTH_TOKEN@default?from=$TWILIO_FROM
阿里云同理:ALIYUN_ACCESS_KEY_ID、ALIYUN_ACCESS_KEY_SECRET、ALIYUN_REGION_ID、ALIYUN_DSN 缺一不可,错一个就路由到空 transport。
Notification::getChannels() 必须动态返回,不能硬编码
通知类里的 getChannels() 方法决定最终走哪些渠道。硬编码 ['email', 'sms'] 是高频翻车点——用户没填手机号,系统仍尝试发短信,失败后无提示。
推荐写法是根据接收者状态判断:
public function getChannels(): array
{
return $this->recipient->getPhone() ? ['sms'] : ($this->recipient->getEmail() ? ['email'] : []);
}
更复杂的策略(如 VIP 用户双渠道、普通用户单渠道)应交给自定义 ChannelPolicy,而不是塞进通知类里做 if-else。
本地开发别漏掉 NullTransport 和 debug 工具
开发时真发短信/邮件既费钱又难调试。用 null:// 替代真实 transport 最安全:
texter_transports:
sms: 'null://'
但要注意:这个配置不能放在主 notifier.yaml 里污染生产环境,得单独建 notifier_dev.yaml 并用 when@dev 导入。
想确认 DSN 是否解析成功、transport 是否启用,运行:
php bin/console notifier:transport:debug
它会列出每个 transport 的状态、DSN 解析结果和 HTTP 连接测试响应。比翻日志快得多。
真正容易被忽略的是:Notifier 的“渠道”不是开关,而是路由规则;它不保证送达,只负责把消息扔给对应 transport —— 后者是否连通、API 是否限流、凭证是否过期,都得自己盯住 debug 输出和 transport 日志。


















