Symfony Notifier需先配置邮件(smtp://)和短信(如twilio://)DSN,启用对应通道;Notification须实现NotificationInterface并动态返回channels,Recipient须实现getEmail()/getPhone();默认同步发送需改异步以避免阻塞。

如何配置 Symfony Notifier 的短信/邮件通道
Symfony Notifier 本身不发消息,它只负责把 Notification 转成 ChatMessage、EmailMessage 等具体类型,再交给对应通道(channel)执行。所以第一步不是写逻辑,而是配通路。
常见错误是只装包没配 DSN,结果调用 notifier->send() 完全静默,连日志都不报错——因为默认通道是 chat,而你根本没配任何 chat provider。
- 邮件通道依赖
symfony/mailer,DSN 格式为smtp://user:pass@host:port,必须确保MAILER_DSN环境变量已设或在config/packages/notifier.yaml中显式声明 - 短信通道(如 Twilio)需单独安装
symfony/twilio-notifier,DSN 是twilio://sid:token@default?from=+1234567890;国内厂商如阿里云、腾讯云需自己写自定义 transport,官方不内置 - 多个通道可同时启用,但
notifier.send()默认只走admin通道;如要发给用户,得用$notifier->send($notification, $recipient),且$recipient必须实现RecipientInterface并提供getEmail()或getPhone()
Notification 和 Recipient 怎么写才不踩坑
很多人直接 new Notification,结果收不到——因为 Notifier 不识别裸对象。必须让通知类实现 NotificationInterface,且 recipient 要能被解析出联系方式。
典型错误:用数组或字符串当 recipient,或在 getChannels() 里硬编码 ['email'] 却没检查用户是否填了邮箱。
立即学习“PHP免费学习笔记(深入)”;
-
Notification类里getChannels()应动态返回,比如:return $recipient->getEmail() ? ['email'] : ($recipient->getPhone() ? ['sms'] : []); -
Recipient类必须实现getEmail()、getPhone()、getChatName()等方法,哪怕返回 null;Notifier 会按 channel 名自动调这些方法,不满足就跳过 - 别在
__construct()里塞太多逻辑,Notification 是无状态的,内容应靠getContent()动态生成,否则缓存或序列化时容易出问题
为什么 send() 没报错但消息没发出去
最常发生于开发环境:Mailer 默认用 sendmail 或 native transport,但本地没装 sendmail,或权限不对,结果消息进了黑洞,日志里只有 Message sent 假象。
另一个隐蔽点是 Twig 模板路径写错——Notifier 用 email.html.twig 渲染邮件,但如果你放在 templates/notification/ 下却没在 Notification::getTemplate() 里指定完整路径,就会 fallback 到空模板,发个空邮件。
- 强制查看真实发送行为:在 .env 加
MAILER_DSN=smtp://null@localhost,再跑命令php bin/console notifier:transport:debug,看哪些 transport 处于 enabled 状态 - 发邮件前加
dd($message->getSubject(), $message->getBody());在EmailNotification::asEmail()里,确认内容生成正常 - 短信调试建议用
log://DSN 先验证流程,避免扣费或触发风控
性能和扩展性要注意什么
Notifier 默认同步执行,一个通知触发多个通道(比如同时发邮件+短信+Slack),会卡住响应。线上必须改异步,但很多人只配了 Messenger,忘了加 async 标签。
更麻烦的是自定义通道——比如对接国内短信平台,Transport 类里如果用了 file_get_contents() 或没设超时,一个接口 hang 住,整个队列就堵死。
- 异步必需两步:①
composer require symfony/messenger;② 在 transport DSN 后加?transport=async,例如smtp://...?transport=async - 自定义 Transport 必须实现
TransportInterface,且send()方法里要用try/catch包住 HTTP 请求,并设timeout和connect_timeout - 别在
Notification里查数据库或调外部 API,内容应在 controller 层准备好传入,保持通知对象轻量
真正难的不是配通路,而是让每个 channel 的失败能被单独捕获、重试、告警。Notifier 把 transport 错误吞得很干净,得自己在 TransportFactory 或 Messenger middleware 里补日志和监控。



















