不能“一键”对接三个平台,因Slack需Webhook URL配置、钉钉需手动实现ChatterInterface、Telegram有4096字节长度限制且需手动分片,三者认证方式、消息格式及错误处理逻辑完全不同。

不能“一键”对接三个平台——Notifer 的 transport 必须分别配置,且每个平台的认证方式、消息格式、错误处理逻辑完全不同。所谓“一键”只是指共用同一个 Notifier 接口调用,底层 transport 仍需独立声明、测试和维护。
Slack transport 配置必须用 webhook URL,别碰 OAuth 流程
Slack 官方不支持 Notifier 的 OAuth2 transport(slack://oauth);Symfony 官方文档里写的 slack://token@default 也早已失效。唯一稳定可用的是 Incoming Webhook:
- 在 Slack 工作区设置 → “自定义集成” → “Incoming Webhooks” 创建,拿到类似
https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX的 URL - 配置写成
SLACK_DSN=slack://xoxb-...@default是错的;正确写法是SLACK_DSN=slack://webhook@default?webhook_url=https%3A%2F%2Fhooks.slack.com%2Fservices%2F... - 注意 URL 必须 URL-encoded,否则容器启动时会报
Invalid DSN: malformed - 发送时若收到
400 Bad Request,大概率是 payload 中text字段为空或含非法字符(比如未转义的\n或 emoji)
钉钉 transport 要自己写 Chatter,官方没提供现成实现
Symfony Notifier 官方包(v6.4+)至今不包含钉钉 ChatterInterface 实现。你必须手动注册一个:
- 新建类
DingTalkChatter实现ChatterInterface,用 cURL 或HttpClientPOST 到钉钉机器人地址(https://oapi.dingtalk.com/robot/send?access_token=xxx) - 消息体必须是 JSON,
msgtype推荐用text或markdown;atMobiles和isAtAll要显式控制,否则默认不@任何人 - 在
config/services.yaml中注册为ding_talk.chatter,再通过notifier.transport_factory扩展注入到 transport 链路 - 别直接改
notifier.yaml加dingtalk://...—— 没有对应 factory,会抛Unknown transport "dingtalk"
Telegram transport 依赖 bot token,但消息长度超 4096 字节就静默失败
Telegram 对单条消息长度限制极严,且 Notifier 不做分片,超长内容直接被 API 拒绝(返回 400 Bad Request,body 含 "message_text is too long"):
- DSN 格式为
TELEGRAM_DSN=telegram://123456789:ABC-DEF1234ghIkl-zyx57W2v1u123ew11?chat_id=-1001234567890,其中chat_id可正(用户)可负(群组),负数必须带-100前缀 - 发消息前务必用
mb_strlen($text, 'UTF-8')检查长度,超过 4096 就要手动切片(按 UTF-8 字符切,不是字节) - 切片后逐条发送,别用
sleep()控制频率——Telegram 有 30 msg/sec 限流,应使用HttpClient的 retry policy + exponential backoff - 别忽略
parse_mode参数:设成html才能渲染<b>、<a>等标签,但必须确保 HTML 标签闭合且无嵌套错误,否则整条消息被丢弃
三个平台真正共通的只有 Notification 和 Channel 抽象层;transport 层的差异远大于相似性。最容易被忽略的是钉钉没有官方 chatter 实现——很多人卡在“找不到 dingtalk:// 支持”就停了,其实得自己写;而 Telegram 的长度截断问题,在本地测试时往往因消息短而漏测,上线后才突然失联。


















