下载地址
https://www.zhengdianxue.com/wp-content/uploads/skills/hynn--dingtalk-message-sender.zip将提示词发送给你的 AI 安装该 skills
请根据 https://skillhub.cn/install/skillhub.md,安装 @hynn/dingtalk-message-sender。钉钉消息批量发送底座:单聊 / 群聊 / DING 三类通知的消息构造、发送前预览确认、并行分批发送与逐条送达状态核对,并沉淀钉钉聊天 Markdown 渲染规则。当用户要求批量发送钉钉通知、提醒催办、@多人、发送培训/参会/绩效等事项通知时使用。不用于:单条普通消息(走 dingtalk-chat)、邮件(走 dingtalk-mail)、读取或检索收到的消息(走 dingtalk-chat)。
阅读全文 (展开查看完整说明)
概述
把「要发给一批人」这件事收口成一条可核验的流水线:预览先行 → 并行分批直调 → 逐条确认送达。所有催办、提醒、通知类业务技能都复用这套发送底座,避免各自手写一套发送逻辑。
适用与不适用
- 适用:给多人发同一主题的钉钉通知;按人差异化的催办消息;群聊 @ 指定成员;任务完成后按需发应用内 DING;发送失败后的安全续发。
- 不适用:只发一条普通消息 → 直接用
dingtalk-chat;发邮件 →dingtalk-mail;查/收消息、检索历史 →dingtalk-chat或dingtalk-aisearch;处理审批单据 →dingtalk-misc;紧急电话/短信类触达本技能不涉及。
前置配置(首次使用填写)
真实坐标一律不写进技能正文,存放在本地坐标登记表(模板见 [references/coordinates.md](references/coordinates.md)):
<SELF_USER_ID>:本人钉钉 userId,dws profile list获取<ROBOT_CODE>:完成通知用的机器人 robot-code(可选),dws chat bot list或向管理员领取<CID_TARGET>:常用目标群 openConversationId,dws chat search --query "<群名>"获取- 收件人 userId:按姓名实时查询(
dws contact user search/dws aisearch),只在会话内缓存,不写入技能
核心发送方式(铁律,违反即失效)
- Bash 直调:dws 命令必须由 Bash 工具直接调用(由宿主侧执行)。禁止用 Python subprocess / 脚本封装 / shell 重定向调用 dws——只会拿到 pending 占位符,消息不会真正发出。
- 一条一调:每条消息一个独立的 Bash 调用。禁止在 Python/循环/
&&链里串接多条 dws(易报 framing invalid),禁止$(...)命令替换包装。 - 并行分批:多条消息时在同一响应里并行发出多个 Bash 调用,每批 2-4 条,看完本批结果再发下一批;禁止一次并发过多。
- 幂等 UUID:每条消息带
--uuid,语义化命名<主题>-<日期YYYYMMDD>-<收件人拼音>,例如weekly-report-20260101-zhangsan。失败重发、登录失效后续发、会话中断后恢复一律复用同一 UUID,防止重复发送。 - 送达确认:send 返回
outcome=pending+openTaskId属正常现象(异步提交),不是失败。每条发送后执行
dws chat message query-send-status --open-task-id <openTaskId> --format json确认 sendStatus=SUCCESS 才算送达。
参数速查
dws chat message send:正文用--text(真实换行可直接传递,字面n不会被转换)、--title、--user <userId>、--uuiddws ding message send:正文用--content(不是--text)、--robot-code、--users、--type app- 群消息:
dws chat message send --conversation-id <CID_TARGET>;@ 全员用--at-all且正文含<@all>占位符;@ 指定人时--at-open-dingtalk-ids与正文中的<@openDingTalkId>占位符必须一一对应 - 已发消息可用
dws chat message edit --msg-id …补正 @ 关系,不必重发 - 大输出加
--jq投影压缩;输出超限被截断时,完整结果在临时 hook-output 文件里,另行读取
聊天 Markdown 渲染规则
- 单换行会被合并成空格,分段必须双换行
- 列表用
-/1.加空格,项间单换行(夹空行会丢列表样式);1、顿号不换行 - 多级内容改用
**N. 标题**:正文加粗段落 + 空行分隔;##***>与链接正常;列表项内的<br>无效 message list返回内容有损,不能当作渲染效果的验证依据
标准流程
- 解析收件人:姓名 → userId;同一会话内已验证过的 userId 直接复用,避免重复查询
- 构造消息:按渲染规则写正文;多事项必须逐行换行;给收件人的措辞只描述客观字段状态,不带主观判断词
- 预览确认:在回复正文里完整展示每条消息原文(收件人、标题、正文、UUID),再用 AskUserQuestion 让用户选择(确认发送 / 需要修改 / 调整收件范围)
- 并行分批发送:每批 2-4 条 Bash 直调,逐条检查返回的
openTaskId - 送达确认:对 pending 的每条执行
query-send-status,确认 SUCCESS - 汇总报告:按收件人列出发送结果与失败明细;如用户配置了完成通知机器人,再发一条 DING(可选步骤,前缀按团队约定,如「来自 <工具名> | 任务完成:<描述>」)
消息构造规则与取舍
- 群发前先单聊发本人测格式(换行在钉钉端最容易错位),确认无误再发群
- 含链接的消息先验证链接可达且指向正确对象,再进入发送队列
- 同一批通知的收件人范围以用户当次指定为准,不自行扩展;漏发比多发容易补救
- 抄送类判断(如参训人的直属上级恰好是用户本人)须先问,默认不发
Pitfalls(实测沉淀)
- Python subprocess 陷阱:脚本内调 dws 拿到的 pending 是占位符假象,没有可查的
openTaskId、消息实际未发出——该路径已多次验证失效,勿再尝试 - 登录失效中断:发送中途报 token/identity 错误时,提示用户在「设置 > 连接器」重新登录;恢复后按原 UUID 续发,已 SUCCESS 的不重发
- 偶发 identity changed during token resolution:加
--verbose原样重试一次即可 - 把 pending 当失败:
message send顶层ok: true(success在 data 内)、+dm顶层success: true,两者结构不同;用同一套.get("success")判断会把成功的群消息误判为失败进而重发 - 末尾反斜杠 / 特殊字符:正文结尾的反斜杠会转义闭合引号导致命令被拦截;避免
§、裸括号与结尾反斜杠 - 无 uuid 重发:不带
--uuid的失败重试最容易造成同一人收到两条相同通知
Verification
- [ ] 每条消息
query-send-status返回sendStatus=SUCCESS - [ ] 汇总报告条数 = 用户确认发送的收件人数,无遗漏、无重复
- [ ] 每条消息的
--uuid与预览时一致(可反查是否重发) - [ ] 正文在钉钉端渲染正确(分段空行、列表样式、@ 高亮生效),而非仅本地文本正确
- [ ] 未经用户确认的消息未被发出(预览环节不可跳过)
资源
- [references/coordinates.md](references/coordinates.md) —— 坐标登记表模板(真实 ID 本地填写,勿提交)