使用DingtalkChatbot库最省事,5行代码即可发送带@的告警文本;需注意secret配置、at_mobiles格式为字符串列表、is_at_all依赖群设置;手动加签易错在时间戳单位、签名原文换行符及quote_plus编码。

直接用 DingtalkChatbot 库最省事,5行代码就能发文本告警;但如果你手动拼请求,加签逻辑写错、时间戳过期、atMobiles 格式不对,都会导致消息发不出或不触发@——这些是90%新手卡住的地方。
用 DingtalkChatbot 发送带 @ 的告警文本
这是最快落地的方式,封装了加签、超时重试和参数校验,避免自己踩坑:
- 先安装:
pip install dingtalkchatbot - 初始化时必须传
secret(如果钉钉机器人开启了加签),否则会 403 -
send_text的at_mobiles参数要传字符串列表,不是逗号分隔的字符串,比如["13812345678"],不是"13812345678" - 如果想 @所有人,把
is_at_all=True,但注意:群设置里必须允许“@所有人”,否则无效
示例:
from dingtalkchatbot.chatbot import DingtalkChatbot <p>webhook = "<a href="https://www.php.cn/link/93b5129e24b9c92e5b8e7115056b46bd">https://www.php.cn/link/93b5129e24b9c92e5b8e7115056b46bd</a>" secret = "xxxxx" # 加签密钥,没开加签可省略</p><p>xiaoding = DingtalkChatbot(webhook, secret=secret) xiaoding.send_text( msg="【告警】服务 user-api 响应延迟 > 2s", at_mobiles=["13812345678", "13987654321"] ) </p>
手动构造加签 URL 容易出错的三个点
不用 SDK 时,加签逻辑必须严格对齐钉钉要求,稍有偏差就返回 {"errcode":310000,"errmsg":"invalid signature"}:
- 时间戳单位是毫秒,且必须是整数(
int(time.time() * 1000)),不能带小数点 - 签名原文格式是
"{timestamp}\n{secret}",换行符是\n,不是\r\n或空格 - Base64 编码后必须用
urllib.parse.quote_plus编码,不能用quote或手动替换
错误写法示例(会导致签名失败):
# ❌ 错误:用了 quote 而非 quote_plus sign = urllib.parse.quote(base64.b64encode(hmac_code)) <h1>✅ 正确</h1><p>sign = urllib.parse.quote_plus(base64.b64encode(hmac_code)) </p>
发送 Markdown 消息提升可读性
纯文本告警信息密度低,用 send_markdown 可高亮关键指标、加链接、分段,运维排查更快:
- 标题用
##开头,不要用#(钉钉只渲染到二级标题) - 链接必须是完整 URL(
http://或https://开头),相对路径无效 -
at_mobiles在 markdown 模式下依然生效,但不会自动在消息末尾补上 @ 提醒,需手动写进内容里
示例:
xiaoding.send_markdown(
title="【P1 紧急告警】",
text="## 服务异常\n- **服务名**:order-service\n- **错误率**:12.7%(阈值 2%)\n- [查看详情](https://grafana.example.com/d/abc/order-errors)\n> @13812345678 @13987654321 请立即介入",
at_mobiles=["13812345678", "13987654321"]
)
生产环境必须处理的两个失败场景
网络抖动或钉钉限流(每分钟最多20条)会导致发送失败,但脚本不能静默吞掉错误:
- 检查响应状态码:非
200一律视为失败,不要只看errcode == 0 - 捕获
requests.exceptions.RequestException,记录日志并考虑降级(比如写入本地文件或发邮件) - 如果连续失败,别盲目重试——钉钉对频繁失败 IP 会临时封禁,建议加指数退避
关键判断逻辑:
try:
resp = requests.post(signed_url, json=data, timeout=5)
if resp.status_code != 200:
log.error(f"DingTalk API error: {resp.status_code} {resp.text}")
except requests.exceptions.RequestException as e:
log.error(f"Network error: {e}")
加签密钥和 webhook 地址一旦写死在代码里,上线后就很难轮换;真正稳定的方案是通过环境变量或配置中心加载,而不是改代码再部署。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











