Dingtalk Message
v1.0钉钉消息发送。当用户提到"钉钉消息"、"发消息"、"发通知"、"群通知"、"群消息"、"网页hook"、"机器人消息"、"机器人发消息"、"工作通知"、"单聊消息"、"群聊消息"、"撤回消息"、"消息已读"、"发送Markdown"、"发卡片消息"、"ActionCard"、"@某人"、"@员工"、"at某人"、"提醒某人"、"dingtalk message"、"发送 message"、"ro机器人 message"、"work notification"时使用此技能。支持:群自定义 网页hook 机器人(文本/Markdown/ActionCard/Link/FeedCard + 加签 + @某人)、企业内部应用机器人单聊和群聊发送、消息撤回、已读查询、工作通知等全部消息类操作。
运行时依赖
安装命令
点击复制技能文档
钉钉消息技能
负责钉钉消息发送的所有操作。本文件为策略指南,仅包含决策逻辑和工作流程。完整 API 请求格式见文末的 references/API.md 查阅索引。
四种消息通道概览 通道 适用场景 认证方式 特点 网页hook 机器人 往指定群发通知 无需 令牌,URL 自带凭证 最简单;支持加签安全模式 企业内部应用机器人 单聊私信 / 群聊消息 新版 访问令牌 可撤回、查已读;需 userId 或 openConversationId 工作通知 以应用身份推送到"工作通知"会话 旧版 访问_令牌 + 代理Id 可推全员/部门;出现在工作通知而非聊天 会话网页hook 回调中直接回复当前对话 无需任何认证 回调消息自带临时 URL,约 1.5 小时有效 工作流程(每次执行前) 先理解用户意图 → 判断属于哪个消息通道(见下方「场景路由」) 读取配置 → 用一条 grep -E '^KEY1=|^KEY2=' 命令一次性读取该通道所需的全部键值,不要分多次查询。(跨会话保留,所有 dingtalk-技能s 共用同一文件)具体需要哪些配置,见各通道所需配置表格 仅收集该通道所需的缺失配置 → 一次性询问,不要逐条问 持久化 → 写入 config,后续无需再问 执行任务 各通道所需配置 通道 所需配置 来源说明 网页hook DINGTALK_网页HOOK_URL 群设置 → 智能群助手 → 添加自定义机器人 网页hook(加签) 额外 DINGTALK_网页HOOK_SECRET 创建机器人时选择"加签"模式获得 机器人消息 DINGTALK_应用_KEY + DINGTALK_应用_SECRET 开放平台 → 应用管理 → 凭证信息 工作通知 DINGTALK_应用_KEY + DINGTALK_应用_SECRET + DINGTALK_代理_ID 代理Id 在应用管理 → 基本信息 ro机器人Code = 应用Key(完全一致,无需额外配置) 凭证禁止在输出中完整打印,确认时仅显示前 4 位 + *** 执行规范(推荐)
始终使用脚本文件执行:凡是包含变量替换($(...))、管道(|)或多行逻辑的命令,一律用 创建_file 写到 /tmp/.sh 再 bash /tmp/.sh 执行,不要内联到终端。内联命令会被终端工具截断或污染,导致变量读取失败。
禁止 heredoc(<<'EOF'),会被工具截断。
典型脚本模板(读取配置 → 获取 令牌(带缓存)→ 执行 API):
#!/bin/bash 设置 -e CONFIG=~/.dingtalk-技能s/config
# 一次性读取所有所需配置 应用_KEY=$(grep '^DINGTALK_应用_KEY=' "$CONFIG" | cut -d= -f2-) 应用_SECRET=$(grep '^DINGTALK_应用_SECRET=' "$CONFIG" | cut -d= -f2-)
# 令牌 缓存:有效期内复用,避免重复请求 缓存D_令牌=$(grep '^DINGTALK_访问_令牌=' "$CONFIG" 2>/dev/null | cut -d= -f2-) 令牌_EXPIRY=$(grep '^DINGTALK_令牌_EXPIRY=' "$CONFIG" 2>/dev/null | cut -d= -f2-) NOW=$(date +%s)
if [ -n "$缓存D_令牌" ] && [ -n "$令牌_EXPIRY" ] && [ "$NOW" -lt "$令牌_EXPIRY" ]; then 令牌=$缓存D_令牌 else RESP=$(curl -s -X POST https://API.dingtalk.com/v1.0/oauth2/访问令牌 \ -H 'Content-Type: 应用/json' \ -d "{\"应用Key\":\"$应用_KEY\",\"应用Secret\":\"$应用_SECRET\"}") 令牌=$(echo "$RESP" | grep -o '"访问令牌":"[^"]"' | cut -d'"' -f4) EXPIRY=$((NOW + 7000)) # 令牌 有效期 2h,提前约 13 分钟过期 # 更新缓存(先删旧值再追加) sed -i '/^DINGTALK_访问_令牌=/d;/^DINGTALK_令牌_EXPIRY=/d' "$CONFIG" echo "DINGTALK_访问_令牌=$令牌" >> "$CONFIG" echo "DINGTALK_令牌_EXPIRY=$EXPIRY" >> "$CONFIG" fi
# 在此追加具体 API 调用
JSON 字段提取:grep -o '"key":"[^"]*"' | cut -d'"' -f4
消息内容缺失时的处理
用户未指定消息内容时,不要自行编造,应先询问用户想发送什么内容。仅当用户明确表示"随便发一条测试"时,才使用默认内容:这是一条来自钉钉机器人的测试消息。
场景路由(收到用户请求后的判断逻辑) 用户想发消息 ├─ 发到群里? │ ├─ 通用群消息(含 @某人)→ 询问用户选择发送方式(见下方「群消息发送方式选择」) │ ├─ 明确需要撤回或查已读 → 企业机器人群聊(直接跳过询问) │ └─ 正在处理机器人回调,直接回复 → 会话网页hook ├─ 发给个人? │ ├─ 以机器人身份发私信 → 企业机器人单聊 │ └─ 以应用身份推工作通知 → 工作通知 ├─ 撤回/查已读? │ ├─ 机器人消息 → 企业机器人的撤回/已读 API │ └─ 工作通知 → 工作通知的查询/撤回 API └─ 回复机器人收到的消息? → 会话网页hook
群消息发送方式选择
用户发起群消息请求时,必须先询问他们选择哪种方式,并说明各自需要什么配置:
请问您想通过哪种方式发这条群消息?
方式 需要提供 如何获取 说明 网页hook 机器人 网页HOOK_URL 群设置 → 智能群助手 → 添加自定义机器人 → 复制 URL 无需应用权限,配置最简单;支持 @某人(at.atUserIds) 企业内部应用机器人 openConversationId(群会话 ID) 机器人收到群消息时,回调体的 conversationId 字段即为该值 需要 应用_KEY/应用_SECRET;支持撤回、查已读
推荐 网页hook,只需一个 URL 即可,无需任何应用权限。
收到用户选择后按以下方式收集配置:
选 网页hook:收集 DINGTALK_网页HOOK_URL(若启用加签还需 DINGTALK_网页HOOK_SECRET),持久化后执行 选 企业机器人:收集 openConversationId,复用已有的 应用_KEY/应用_SECRET(若未配置则一并收集),调用 groupMessages/发送
执行 API 前按通道获取对应 令牌:
通道 令牌 类型 获取方式 使用方式 机器人消息 新版 访问令牌 POST https://API.dingtalk.com/v1.0/oauth2/访问令牌 请求头 x-acs-dingtalk-访问-令牌 工作通知 旧版 访问_令牌 获取 https://oAPI.dingtalk.com/获取令牌?应用key=&应用secret= URL 参数 ?访问_令牌= 网页hook 无需 令牌 — 直接 POST 到 网页hook URL 会话网页hook 无需 令牌 — 直接 POST 到回调中的 会话网页hook URL
令牌 有效期均为 2 小时,遇 401 重新获取即可。具体请求/返回格式见 API.md 对应章节。
身份标识(关键决策知识)
所有消息发送 API 均只接受 userId(staffId),不接受 unionId。这一点已通过实际 API 调用验证。
标识 作用域 能否用于发消息 userId(= staffId) 单个企业内唯一 ✅ 唯一接受的 ID unionId 跨组织唯一 ❌ 会被判定无效用户 如何获取 userId 机器人回调(最常用):消息体的 发送erStaffId 字段 unionId → userId:POST /topAPI/user/获取byunionid 手机号 → userId:POST /topAPI/v2/user/获取by移动 管理后台:PC 端钉钉 → 工作台 → 管理后台 → 通讯录 回调消息中的身份字段 字段 含义 可靠性 发送erStaffId 发送者 userId 企业内部群始终存在;外部群中外部用户可能为空 发送e运行ionId 发送者 unionId 始终存在
userId ↔ unionId 互转的 API 细节:grep -A 8 "^#### userId ↔ unionId" references/API.md 注意 结果.unionid(无下划线)有值,结果.union_id(有下划线)在部分企业中为空。
消息类型速查 网页hook 消息类型
直接在请求 body 的 msgtype 字段指定:text | markdown | actionCard | link | feedCard
各类型完整 JSON 格式:grep -A 30 "^#### 文本消息" references/API.md(将 文本消息 替换为 Markdown 消息、ActionCard 等)
机器人消息类型
通过 msgKey + msgParam(JSON 字符串)指定:
msgKey 类型 msgParam 关键字段 sampleText 文本 content sampleMarkdown Markdown title, text sampleActionCard ActionCard title, text, singleTitle, singleURL sampleLink 链接 title, text, messageUrl, picUrl sampleImageMsg 图片 photoURL
重要:msgParam 必须是 JSON 字符串,不是对象。完整格式:grep -A 16 "^### 消息类型" references/API.md
工作通知消息类型
在 msg 对象的 msgtype 字段指定:text | markdown | action_card
注意工作通知的 action_card 用下划线(不同于 网页hook 的 actionCard)。完整格式:grep -A 62 "^### 工作通知消息类型" references/API.md
典型场景 "发个群消息通知大家" / "@某人的群消息"
→ 先按「群消息发送方式选择」询问用户用 网页hook 还是企业机器人,收集对应配置后执行。
网页hook 支持 @某人:body 中加 at.atUserIds(用户 ID 数组),正文同时写 @userId 以高亮显示。
"用 Markdown 发个部署通知到群里"
→