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

Faster-Whisper-GUI日语语音识别完整指南:从零开始轻松转写日语音频

Faster-Whisper-GUI日语语音识别完整指南:从零开始轻松转写日语音频 【免费下载链接】faster-whisper-GUIfaster_whisper GUI with PySide6 项目地址: https://gitcode.com/gh_mirrors/fa/faster-whisper-GUI Faster-Whisper-GUI是一个基于PySide6开发的图形界面工具,专门用于日语语音识别和音频转写。这款工具通过优化算法和直观界面,让日语语音识别变得简单高效。无论你是日语学习者、内容创作者还是需要处理日语音频的专业人士,都能快速上手使用。 🎯 为什么选择Faster-Whisper-GUI进行日语识别? Faster-Whisper-GUI相比其他语音识别工具具有明显优势: * 多模型支持:兼容Whisper、WhisperX等多种模型,确保日语识别精度 * 硬件加速:支持CUDA显卡加速,大幅提升处理速度 * 时间轴输出:自动生成日语文本的时间标记,便于后续编辑 * 免费开源:完全免费使用,无需订阅费用 ⚙️ 三步完成日语语音识

AI 智能编码工具:重塑开发效率的革命,从 GitHub Copilot 到国产新秀的全面解析

AI 智能编码工具:重塑开发效率的革命,从 GitHub Copilot 到国产新秀的全面解析

目录 引言 一、主流智能编码工具深度测评:从功能到实战 1. GitHub Copilot:AI 编码的 “开山鼻祖” 核心特性与实战代码 优缺点总结 2. Baidu Comate:文心大模型加持的 “国产之光” 核心特性与实战代码 优缺点总结 3. 通义灵码:阿里云的 “企业级编码助手” 核心特性与实战代码 优缺点总结 引言 作为一名拥有 8 年开发经验的程序员,我曾无数次在深夜对着屏幕反复调试重复代码,也因记不清框架语法而频繁切换浏览器查询文档。直到 2021 年 GitHub Copilot 问世,我才第一次感受到:AI 不仅能辅助编码,更能彻底改变开发模式。如今,智能编码工具已从 “尝鲜选项” 变为 “必备工具”,它们像经验丰富的结对编程伙伴,能精准补全代码、生成测试用例、

Stable-Diffusion-v1-5-archiveWeb UI高级功能:图生图/局部重绘/蒙版编辑实操指南

Stable Diffusion v1.5 Archive Web UI 高级功能:图生图/局部重绘/蒙版编辑实操指南 1. 引言:从文生图到创意编辑 如果你已经熟悉了 Stable Diffusion v1.5 Archive 的基础文生图功能,可能会发现,仅仅依靠文字描述来生成完美的图片,有时就像在黑暗中摸索。你想要一个特定的人物姿势,但描述了半天,出来的结果总是差那么一点;或者你生成了一张不错的风景图,但天空的颜色不够理想,想单独调整一下。 这时候,就需要用到 Web UI 中更强大的“图生图”功能了。它不再是“无中生有”,而是“有中生优”。你可以上传一张参考图,让 AI 在此基础上进行二次创作、风格迁移,或者只修改图片的某个局部区域。这大大提升了创作的灵活性和可控性。 本文将带你深入探索 Stable

故障排除大全:Llama Factory常见错误与解决方案

故障排除大全:Llama Factory常见错误与解决方案 如果你正在使用Llama Factory进行大模型微调,却频繁遇到各种报错信息,而官方文档又缺乏详细解释,那么这篇文章就是为你准备的。Llama Factory作为一个开源的低代码大模型微调框架,确实简化了训练流程,但在实际使用中,新手用户还是会遇到各种问题。本文将汇总最常见的错误及其解决方案,帮助你顺利度过微调难关。 这类任务通常需要GPU环境,目前ZEEKLOG算力平台提供了包含该镜像的预置环境,可快速部署验证。但无论你使用哪种环境,下面的解决方案都适用。 环境配置常见问题 CUDA版本不兼容 这是最常见的错误之一,通常表现为类似CUDA error: no kernel image is available for execution的报错。 1. 首先检查你的CUDA版本是否与PyTorch版本匹配: bash nvcc --version python -c "import torch; print(torch.__version__)" 1. 如果发现不匹配,可以尝试以下解决方案: 2.