openclaw 钉钉 Webhook 完全指南

📮 钉钉 Webhook 完全指南

整理者:✨ 小琳 | 更新于 2026-02-05

一、基础知识

Webhook vs 插件

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

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

消息格式支持

格式插件Webhook
纯文本
Markdown
链接卡片
按钮卡片
@ 用户

二、@ 用户功能

核心原理

两个地方必须同时设置:

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

缺一不可!

JSON 示例

@ 所有人:

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

@ 指定用户:

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

@ 多个用户:

{
  "msgtype": "text",
  "text": {
    "content": "@13800138000 @13900139000 请查看"
  },
  "at": {
    "atMobiles": ["13800138000", "13900139000"],
    "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"]="16670151072"
USERS["琳琳"]="16670151072"
USERS["maple"]="19976618156"
USERS["鸿枫"]="19976618156"
# ===== 配置结束 =====

# 生成时间戳和签名
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': '16670151072',
  '琳琳': '16670151072',
  'maple': '19976618156',
  '鸿枫': '19976618156'
};

/**
 * 生成钉钉签名
 */
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": "16670151072",
    "琳琳": "16670151072",
    "maple": "19976618156",
    "鸿枫": "19976618156"
}

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@13800138000 请在下班前完成以下任务:\n\n- [ ] 代码审查\n- [ ] 更新文档"
  },
  "at": {
    "atMobiles": ["13800138000"]
  }
}


掌握这些,钉钉机器人就能玩出花了! 🚀

本文由 mdnice 多平台发布

Read more

智能车竞赛实战:如何用地瓜机器人打造智慧医疗解决方案(附完整代码)

智能车竞赛实战:基于地瓜机器人的智慧医疗系统开发指南 在当今技术驱动的医疗创新浪潮中,智能车竞赛为大学生创客提供了绝佳的实践平台。地瓜机器人作为一款开源硬件平台,其灵活的可扩展性和丰富的传感器生态,使其成为开发智慧医疗解决方案的理想选择。本文将深入探讨如何从零开始构建一套完整的智慧医疗系统,涵盖硬件选型、算法设计到实战优化的全流程。 1. 硬件架构设计与环境搭建 构建智慧医疗系统的第一步是搭建可靠的硬件基础。地瓜机器人平台的核心优势在于其模块化设计,允许开发者根据具体需求灵活配置传感器和执行机构。 1.1 核心硬件选型建议 对于医疗应用场景,我们需要特别关注数据的准确性和系统的稳定性。以下是经过实战验证的硬件配置方案: * 主控单元:推荐使用地瓜机器人V3.2开发板,其搭载的STM32H743芯片提供充足的算力资源 * 环境传感器: * 温湿度:SHT31高精度数字传感器(±1.5%RH精度) * 空气质量:SGP30 VOC传感器 * 医疗监测模块: * 红外测温:MLX90614非接触式传感器 * 心率血氧:MAX30102光电传感器

手把手用ROS实现Ego-Planner动态避障:无人机撞树问题终结方案

手把手用ROS实现Ego-Planner动态避障:无人机撞树问题终结方案 你是否曾满怀期待地启动无人机,看着它在仿真环境中流畅起飞,却在下一秒“砰”地一声撞上突然出现的障碍物,仿真画面定格,留下一串令人沮丧的报错信息?在复杂、非结构化的真实飞行场景中,比如在枝叶交错的林间穿行,或在有行人、车辆移动的城区执行任务,传统的全局规划器往往显得力不从心。它们规划的路径可能全局最优,但面对瞬息万变的局部环境,反应速度跟不上变化,导致“撞树”成了家常便饭。今天,我们不谈空洞的理论对比,而是聚焦于一个能真正解决这个痛点的方案——Ego-Planner,并带你一步步在ROS和Gazebo搭建的仿真世界里,亲手实现一个能“眼观六路、随机应变”的无人机大脑。 本文面向的是已经具备一定ROS和无人机仿真基础,正被动态避障问题困扰的开发者、研究者或高级爱好者。我们将彻底抛开宏观的算法优劣论述,直接深入到代码配置、参数调优和实战排错层面。你将看到的不是“Ego-Planner实时性更好”这样的结论,而是“如何设置距离场梯度计算的网格分辨率”、“碰撞反作用力系数调到多少能让无人机既灵活又稳定”的具体操作。我们

VRM4U插件完整指南:在Unreal Engine 5中高效处理VRM模型

VRM4U插件完整指南:在Unreal Engine 5中高效处理VRM模型 【免费下载链接】VRM4URuntime VRM loader for UnrealEngine4 项目地址: https://gitcode.com/gh_mirrors/vr/VRM4U 还在为Unreal Engine 5中VRM模型导入的各种技术问题而烦恼吗?今天我要为你详细介绍一款能够彻底优化VRM工作流程的专业工具——VRM4U插件!这款专为UE5设计的VRM文件导入解决方案,让你能够专注于创意实现,而不是技术细节。 项目核心价值:为什么VRM4U是你的最佳选择 VRM4U插件不仅仅是一个格式转换器,它是一套完整的3D角色处理生态系统。通过智能化的技术实现,它解决了VRM模型在UE5环境中面临的多重挑战。 核心问题解决方案: * 自动化的材质系统转换 * 完整的骨骼结构映射 * 动画数据的无缝衔接 * 跨平台性能优化 快速入门:5分钟完成插件配置 获取插件资源 首先需要下载VRM4U插件,使用以下命令获取完整代码库: git clone https://gitcode

OFA-VE在AR内容生成中的应用:实时验证虚拟物体与现实图像逻辑关系

OFA-VE在AR内容生成中的应用:实时验证虚拟物体与现实图像逻辑关系 1. 引言:当虚拟遇见现实,如何确保它们“合情合理”? 想象一下,你正在开发一款增强现实(AR)应用,用户可以通过手机摄像头,在自家的客厅里“放置”一个虚拟的沙发。听起来很酷,对吧?但问题来了:如果用户家的客厅里已经摆满了家具,这个虚拟沙发应该放在哪里才显得真实、不突兀?是悬浮在半空,还是稳稳地落在地板上?它会不会和现实中的茶几“穿模”? 这就是AR内容生成中一个核心且棘手的挑战:逻辑一致性。虚拟物体不仅要“看起来”在现实场景中,更要“在逻辑上”与现实场景融为一体。传统方法往往依赖复杂的3D场景重建和物理引擎计算,过程繁琐且对硬件要求高。 今天,我们要介绍一个能优雅解决这个问题的“智能裁判”——OFA-VE。它不是一个AR开发工具,而是一个尖端的多模态推理系统。它的核心能力是进行“视觉蕴含”分析,简单来说,就是判断一段文字描述是否符合一张图片所展现的事实。 我们将深入探讨,如何利用OFA-VE的这种能力,为AR内容生成流程注入“逻辑验证”