跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像AI 生图工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
编程语言Node.js

钉钉 Webhook 完全指南

钉钉 Webhook 配置与使用指南,涵盖 Webhook 与插件对比、@用户功能原理及实现、Shell/Node.js/Python 三种语言推送脚本示例,以及关键词设置、手机号准确性、发送频率等避坑注意事项。

人间过客发布于 2026/4/9更新于 2026/7/2241 浏览

钉钉 Webhook 完全指南

一、基础知识

Webhook vs 插件
方式优点缺点
OpenClaw 插件集成简单,双向通信只能回复,不能主动发
Webhook 机器人支持主动推送,格式丰富单向,需要自己处理签名

结论:需要主动推送消息时,用 Webhook。

消息格式支持
格式插件Webhook
纯文本✅✅
Markdown✅✅
链接卡片❌✅
按钮卡片❌✅
@ 用户❌✅

二、@ 用户功能

核心原理

两个地方必须同时设置:

  1. 消息内容中包含 @手机号 或 @所有人
  2. JSON 的 at 字段中指定 atMobiles 或 isAtAll

缺一不可!

JSON 示例

@ 所有人:

{
  "msgtype": "text",
  "text": {
    "content": "【紧急通知】@所有人 请立即查看"
  },
  "at": {
    "isAtAll": true
  

}
}

@ 指定用户:

{
  "msgtype": "text",
  "text": {
    "content": "【任务分配】@手机号 请跟进项目进度"
  },
  "at": {
    "atMobiles": ["手机号"],
    "isAtAll": false
  }
}

@ 多个用户:

{
  "msgtype": "text",
  "text": {
    "content": "@手机号 @手机号 请查看"
  },
  "at": {
    "atMobiles": ["手机号", "手机号"],
    "isAtAll": false
  }
}

三、完整 Shell 脚本

支持 @ 用户的钉钉推送脚本:

#!/bin/bash
# dingtalk-notify.sh - 支持 @ 用户的钉钉推送
#
# 用法:
#   ./dingtalk-notify.sh "消息内容"          # 普通发送
#   ./dingtalk-notify.sh "消息内容" all      # @所有人
#   ./dingtalk-notify.sh "消息内容" lin      # @指定用户
#   ./dingtalk-notify.sh "消息内容" lin maple # @多人

MESSAGE="$1"
shift

if [ -z "$MESSAGE" ]; then
  echo "用法:$0 \"消息内容\" [all|用户名...]"
  exit 1
fi

# ===== 配置区域 =====
WEBHOOK_BASE="你的 Webhook 地址"
SECRET="你的加签密钥"

# 用户手机号映射
declare -A USERS
USERS["lin"]="手机号"
USERS["琳琳"]="手机号"
USERS["maple"]="手机号"
USERS["鸿枫"]="手机号"
# ===== 配置结束 =====

# 生成时间戳和签名
timestamp=$(date +%s%3N)
string_to_sign="${timestamp}\n${SECRET}"
sign=$(echo -ne "${string_to_sign}" | openssl dgst -sha256 -hmac "${SECRET}" -binary | base64 | sed 's/+/%2B/g; s/\//%2F/g; s/=/%3D/g')

# 构造 @ 参数
IS_AT_ALL="false"
AT_MOBILES=""
AT_TEXT=""

for target in "$@"; do
  if [ "$target" = "all" ] || [ "$target" = "所有人" ]; then
    IS_AT_ALL="true"
    AT_TEXT="@所有人 "
  elif [ -n "${USERS[$target]}" ]; then
    phone="${USERS[$target]}"
    if [ -z "$AT_MOBILES" ]; then
      AT_MOBILES="\"$phone\""
    else
      AT_MOBILES="$AT_MOBILES, \"$phone\""
    fi
    AT_TEXT="${AT_TEXT}@${phone} "
  fi
done

# 构造完整消息
FULL_MESSAGE="${AT_TEXT}${MESSAGE}"

# 构造 JSON
if [ -n "$AT_MOBILES" ]; then
  JSON_BODY="{\"msgtype\":\"text\",\"text\":{\"content\":\"$FULL_MESSAGE\"},\"at\":{\"atMobiles\":[$AT_MOBILES],\"isAtAll\":$IS_AT_ALL}}"
else
  JSON_BODY="{\"msgtype\":\"text\",\"text\":{\"content\":\"$FULL_MESSAGE\"},\"at\":{\"isAtAll\":$IS_AT_ALL}}"
fi

# 发送请求
curl -s "${WEBHOOK_BASE}&timestamp=${timestamp}&sign=${sign}" \
  -H "Content-Type: application/json" \
  -d "$JSON_BODY"

四、Node.js 实现

const crypto = require('crypto');
const axios = require('axios');

// 配置
const WEBHOOK_BASE = '你的 Webhook 地址';
const SECRET = '你的加签密钥';

// 用户手机号映射
const USER_PHONES = {
  'lin': '手机号',
  '琳琳': '手机号',
  'maple': '手机号',
  '鸿枫': '手机号'
};

/**
 * 生成钉钉签名
 */
function generateSign(secret, timestamp) {
  const stringToSign = `${timestamp}\n${secret}`;
  const hmac = crypto.createHmac('sha256', secret);
  hmac.update(stringToSign);
  return encodeURIComponent(hmac.digest('base64'));
}

/**
 * 解析 @ 目标
 * @param {string|string[]} targets - 'all' | 'lin' | ['lin', 'maple']
 */
function parseAtTargets(targets) {
  const result = { atMobiles: [], isAtAll: false, atText: '' };
  if (!targets) return result;

  const list = Array.isArray(targets) ? targets : [targets];
  for (const t of list) {
    if (t === 'all') {
      result.isAtAll = true;
      result.atText = '@所有人 ';
    } else if (USER_PHONES[t]) {
      result.atMobiles.push(USER_PHONES[t]);
      result.atText += `@${USER_PHONES[t]} `;
    }
  }
  return result;
}

/**
 * 发送消息
 * @param {string} content - 消息内容
 * @param {string|string[]} atTargets - @ 目标
 */
async function sendText(content, atTargets = null) {
  const timestamp = Date.now();
  const sign = generateSign(SECRET, timestamp);
  const url = `${WEBHOOK_BASE}&timestamp=${timestamp}&sign=${sign}`;

  const { atMobiles, isAtAll, atText } = parseAtTargets(atTargets);

  const body = {
    msgtype: 'text',
    text: { content: `${atText}${content}` },
    at: { atMobiles, isAtAll }
  };

  const res = await axios.post(url, body);
  return res.data;
}

// 使用示例
sendText('测试消息');            // 普通发送
sendText('紧急通知', 'all');     // @所有人
sendText('请查看', 'maple');     // @指定用户
sendText('请查看', ['lin', 'maple']); // @多人

五、Python 实现

import requests
import json
import time
import hmac
import hashlib
import base64
import urllib.parse

# 配置
WEBHOOK_BASE = "你的 Webhook 地址"
SECRET = "你的加签密钥"

# 用户手机号映射
USER_PHONES = {
    "lin": "手机号",
    "琳琳": "手机号",
    "maple": "手机号",
    "鸿枫": "手机号"
}

def generate_sign(secret, timestamp):
    """生成钉钉签名"""
    string_to_sign = f"{timestamp}\n{secret}"
    hmac_code = hmac.new(
        secret.encode('utf-8'),
        string_to_sign.encode('utf-8'),
        digestmod=hashlib.sha256
    ).digest()
    sign = urllib.parse.quote_plus(base64.b64encode(hmac_code))
    return sign

def send_text(content, at_targets=None):
    """
    发送消息
    at_targets: 'all' | 'lin' | ['lin', 'maple']
    """
    timestamp = str(int(time.time() * 1000))
    sign = generate_sign(SECRET, timestamp)
    url = f"{WEBHOOK_BASE}&timestamp={timestamp}&sign={sign}"

    # 解析 @ 目标
    at_mobiles = []
    is_at_all = False
    at_text = ""

    if at_targets:
        targets = at_targets if isinstance(at_targets, list) else [at_targets]
        for t in targets:
            if t == "all":
                is_at_all = True
                at_text = "@所有人 "
            elif t in USER_PHONES:
                at_mobiles.append(USER_PHONES[t])
                at_text += f"@{USER_PHONES[t]} "

    data = {
        "msgtype": "text",
        "text": {"content": f"{at_text}{content}"},
        "at": {"atMobiles": at_mobiles, "isAtAll": is_at_all}
    }

    response = requests.post(url, json=data)
    return response.json()

# 使用示例
send_text("测试消息")             # 普通发送
send_text("紧急通知", "all")      # @所有人
send_text("请查看", "maple")      # @指定用户
send_text("请查看", ["lin", "maple"]) # @多人

六、避坑指南

1. 自定义关键词

钉钉要求 Webhook 机器人必须设置「自定义关键词」或「加签」。

  • 如果用关键词:确保消息内容包含设定的关键词
  • 推荐用加签:更灵活,不限制消息内容
2. 手机号必须准确
  • atMobiles 里的手机号必须是用户在钉钉绑定的手机号
  • 用户必须在群内,否则 @ 不生效
3. @ 的两个条件缺一不可

❌ 只在 content 里写 @手机号 → 不生效 ❌ 只在 at.atMobiles 里填手机号 → 不生效 ✅ 两个地方都写 → 生效

4. 避免滥用 @所有人

isAtAll 会打扰所有群成员,仅在紧急情况使用。

5. 发送频率限制

钉钉限制:每分钟最多 20 条消息。建议加发送间隔(1 秒)。


七、Markdown 格式 @ 用户

{
  "msgtype": "markdown",
  "markdown": {
    "title": "任务提醒",
    "text": "### 任务提醒\n\n@手机号 请在下班前完成以下任务:\n\n- [ ] 代码审查\n- [ ] 更新文档"
  },
  "at": {
    "atMobiles": ["手机号"]
  }
}

目录

  1. 钉钉 Webhook 完全指南
  2. 一、基础知识
  3. Webhook vs 插件
  4. 消息格式支持
  5. 二、@ 用户功能
  6. 核心原理
  7. JSON 示例
  8. 三、完整 Shell 脚本
  9. dingtalk-notify.sh - 支持 @ 用户的钉钉推送
  10. 用法:
  11. ./dingtalk-notify.sh "消息内容" # 普通发送
  12. ./dingtalk-notify.sh "消息内容" all # @所有人
  13. ./dingtalk-notify.sh "消息内容" lin # @指定用户
  14. ./dingtalk-notify.sh "消息内容" lin maple # @多人
  15. ===== 配置区域 =====
  16. 用户手机号映射
  17. ===== 配置结束 =====
  18. 生成时间戳和签名
  19. 构造 @ 参数
  20. 构造完整消息
  21. 构造 JSON
  22. 发送请求
  23. 四、Node.js 实现
  24. 五、Python 实现
  25. 配置
  26. 用户手机号映射
  27. 使用示例
  28. 六、避坑指南
  29. 1. 自定义关键词
  30. 2. 手机号必须准确
  31. 3. @ 的两个条件缺一不可
  32. 4. 避免滥用 @所有人
  33. 5. 发送频率限制
  34. 七、Markdown 格式 @ 用户
  • 免费图片AI生成工具免费生成了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
  • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
  • 100+免费在线小游戏爽一把
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • Skills 市场与共享经济实战指南:从 Web 到 AI 架构
  • 突破 LLM 上下文瓶颈:上下文内存虚拟化 CMV 的设计与实践
  • Xinference 实测:Llama3-70B、Qwen2-VL 与 Whisper 并发
  • 数据结构详解:顺序表的原理与实现
  • 算法模拟实战:替换问号、提莫攻击与 Z 字形变换
  • AS3 常用位运算技巧与性能优化实战
  • AIGC 微电影《编钟》制作流程复盘
  • Java 使用 Spire.Doc 实现 HTML 转 XML 与 XPS
  • Windows 下 Node.js 安装与环境配置指南
  • Whisper-large-v3 语音识别实测:准确率对比与工程优化
  • 电信行业数据分析的主要应用场景与价值分析
  • VSCode 自定义 Copilot Agent 及使用 Awesome Agent 模板
  • MySQL 9.5 Windows 版安装配置实战
  • WebSocket 连接教程示例(Spring Boot + STOMP + SockJS + Vue)
  • Visual Studio 2026 GitHub Copilot Agent 模式详解
  • VsCode 远程 SSH 下 Copilot Claude Agent 编辑异常修复
  • 知网 AIGC 检测算法升级解读与应对策略
  • 从 Midjourney 到 Runway:AI 视频生成工具进化史
  • TarsosDSP Java 实时音频处理框架技术详解
  • 数据结构核心:树与二叉树详解

相关免费在线工具

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online

  • JSON 压缩

    通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online

  • JSON美化和格式化

    将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online