Dingtalk File Send

自动将文件上传并发送至钉钉用户,基于当前会话账号绑定。

已扫描
适合谁
需要频繁在钉钉中发送文件的职场人士、使用OpenClaw进行自动化办公的开发者
不适合谁
未配置钉钉账号绑定的用户、无法访问外部网络的内网环境用户
国内可用性
需网络配置。可能需要网络配置或第三方服务可访问。
安装难度
新手友好(★☆☆)。基于终端操作、依赖、API Key 和本地环境要求的初步判断。

安装与下载

openclaw skills install @kenriou/dingtalk-file-send

Skill 说明

命令、参数、文件名以原文为准

钉钉文件发送技能

将文件上传至钉钉媒体服务器,并发送给指定用户。

自动检测当前会话绑定的钉钉账号。

适用场景

请在以下情况使用此技能:

  • “把这个 PDF 发给 [用户]”
  • “通过钉钉转发这个文档”
  • “把这份文件分享给我老板”
  • “上传并发送 [文件名]”

配置(自动)

此技能自动检测当前会话绑定的钉钉账号:

工作原理:

  1. 从 OpenClaw 运行时上下文中读取当前 agent ID
  2. ~/.openclaw/openclaw.json 中查找绑定关系
  3. 匹配 agentIdaccountId → 钉钉凭证

绑定示例:

{
  "bindings": [
    {
      "agentId": "dingtalk-office",
      "match": {
        "channel": "dingtalk",
        "accountId": "office"
      }
    }
  ],
  "channels": {
    "dingtalk": {
      "accounts": {
        "office": {
          "clientId": "your_client_id",
          "clientSecret": "xxx",
          "robotCode": "your_robot_code"
        }
      }
    }
  }
}

注意: 在钉钉 API 中,clientId 用于身份验证,等同于 appKey

工作流程

1. 从会话上下文中检测当前 agentId
2. 查找绑定关系:agentId → accountId
3. 根据 accountId 从 OpenClaw 配置中读取凭证
4. 获取访问令牌
5. 将文件上传至钉钉媒体服务器
6. 向接收者发送文件消息

命令

步骤 1:从当前会话检测账号

OPENCLAW_CONFIG=~/.openclaw/openclaw.json

# 从环境变量获取当前 agent ID(由 OpenClaw 运行时设置)
AGENT_ID="${OPENCLAW_AGENT_ID:-dingtalk-office}"

# 从绑定配置中查找 accountId
ACCOUNT_ID=$(jq -r ".bindings[] | select(.agentId == \"$AGENT_ID\") | .match.accountId" $OPENCLAW_CONFIG)

# 备用方案:若未找到绑定,使用 agent ID 的后缀部分
if [ -z "$ACCOUNT_ID" ] || [ "$ACCOUNT_ID" = "null" ]; then
  # 提取 accountId(例如 "dingtalk-office" → "office")
  ACCOUNT_ID=$(echo "$AGENT_ID" | sed 's/dingtalk-//')
fi

# 读取凭证(clientId 作为 appKey 使用)
APP_KEY=$(jq -r ".channels.dingtalk.accounts[\"$ACCOUNT_ID\"].clientId" $OPENCLAW_CONFIG)
APP_SECRET=$(jq -r ".channels.dingtalk.accounts[\"$ACCOUNT_ID\"].clientSecret" $OPENCLAW_CONFIG)
ROBOT_CODE=$(jq -r ".channels.dingtalk.accounts[\"$ACCOUNT_ID\"].robotCode" $OPENCLAW_CONFIG)

# 验证凭证
if [ "$APP_KEY" = "null" ] || [ "$APP_SECRET" = "null" ] || [ "$ROBOT_CODE" = "null" ]; then
  echo "❌ 账号 '$ACCOUNT_ID' 在 OpenClaw 配置中未找到。"
  echo "当前 agent: $AGENT_ID"
  echo "可用账号: $(jq -r '.channels.dingtalk.accounts | keys | join(", ")' $OPENCLAW_CONFIG)"
  exit 1
fi

步骤 2:获取访问令牌

ACCESS_TOKEN=$(curl -s -X POST "https://api.dingtalk.com/v1.0/oauth2/accessToken" \
  -H "Content-Type: application/json" \
  -d "{\"appKey\":\"$APP_KEY\",\"appSecret\":\"$APP_SECRET\"}" | jq -r '.accessToken')

if [ -z "$ACCESS_TOKEN" ] || [ "$ACCESS_TOKEN" = "null" ]; then
  echo "❌ 获取访问令牌失败。"
  exit 1
fi

步骤 3:上传文件

FILE_PATH="$1"
FILE_NAME=$(basename "$FILE_PATH")

UPLOAD_RESULT=$(curl -s -X POST "https://oapi.dingtalk.com/media/upload?access_token=$ACCESS_TOKEN&type=file&robotCode=$ROBOT_CODE" \
  -F "media=@$FILE_PATH;filename=$FILE_NAME" \
  -H "Expect:")

MEDIA_ID=$(echo "$UPLOAD_RESULT" | jq -r '.media_id')

if [ -z "$MEDIA_ID" ] || [ "$MEDIA_ID" = "null" ]; then
  echo "❌ 上传失败: $UPLOAD_RESULT"
  exit 1
fi

步骤 4:发送文件消息

USER_ID="$2"
FILE_EXT="${FILE_NAME##*.}"

PAYLOAD=$(jq -n \
  --arg robotCode "$ROBOT_CODE" \
  --arg msgKey "sampleFile" \
  --arg mediaId "$MEDIA_ID" \
  --arg fileName "$FILE_NAME" \
  --arg fileType "$FILE_EXT" \
  --arg userId "$USER_ID" \
  '{
    robotCode: $robotCode,
    msgKey: $msgKey,
    msgParam: ({
      mediaId: $mediaId,
      fileName: $fileName,
      fileType: $fileType
    } | tojson),
    userIds: [$userId]
  }')

SEND_RESULT=$(curl -s -X POST "https://api.dingtalk.com/v1.0/robot/oToMessages/batchSend" \
  -H "Content-Type: application/json" \
  -H "x-acs-dingtalk-access-token: $ACCESS_TOKEN" \
  -d "$PAYLOAD")

PROCESS_KEY=$(echo "$SEND_RESULT" | jq -r '.processQueryKey // empty')

if [ -n "$PROCESS_KEY" ]; then
  echo "✅ 文件发送成功!"
  echo "ProcessQueryKey: $PROCESS_KEY"
else
  echo "❌ 发送失败: $SEND_RESULT"
  exit 1
fi

完整脚本

# Dingtalk 文件发送技能

## 使用方法

send_dingtalk_file.sh <文件路径> <用户ID>

该脚本会自动从当前会话中检测钉钉账户,无需额外配置。

## 脚本逻辑说明

#!/bin/bash

使用方法:send_dingtalk_file.sh <file_path> <user_id>

自动检测当前会话中的钉钉账户

set -e

OPENCLAW_CONFIG=~/.openclaw/openclaw.json

检查配置文件是否存在

if [ ! -f "$OPENCLAW_CONFIG" ]; then

echo "❌ OpenClaw 配置文件未找到: $OPENCLAW_CONFIG"

exit 1

fi

检查参数

FILE_PATH="$1"

USER_ID="$2"

if [ -z "$FILE_PATH" ] || [ -z "$USER_ID" ]; then

echo "使用方法: $0 <file_path> <user_id>"

exit 1

fi

if [ ! -f "$FILE_PATH" ]; then

echo "❌ 文件不存在: $FILE_PATH"

exit 1

fi

从环境变量获取当前代理 ID(由 OpenClaw 运行时设置)

AGENT_ID="${OPENCLAW_AGENT_ID:-dingtalk-office}"

从绑定信息中查找 accountId

ACCOUNT_ID=$(jq -r ".bindings[] | select(.agentId == \"$AGENT_ID\") | .match.accountId" $OPENCLAW_CONFIG)

如果未找到绑定信息,使用代理 ID 的后缀作为 accountId

if [ -z "$ACCOUNT_ID" ] || [ "$ACCOUNT_ID" = "null" ]; then

ACCOUNT_ID=$(echo "$AGENT_ID" | sed 's/dingtalk-//')

fi

从 OpenClaw 配置中读取凭证

APP_KEY=$(jq -r ".channels.dingtalk.accounts[\"$ACCOUNT_ID\"].clientId" $OPENCLAW_CONFIG)

APP_SECRET=$(jq -r ".channels.dingtalk.accounts[\"$ACCOUNT_ID\"].clientSecret" $OPENCLAW_CONFIG)

ROBOT_CODE=$(jq -r ".channels.dingtalk.accounts[\"$ACCOUNT_ID\"].robotCode" $OPENCLAW_CONFIG)

验证凭证

if [ "$APP_KEY" = "null" ] || [ "$APP_SECRET" = "null" ] || [ "$ROBOT_CODE" = "null" ]; then

echo "❌ 账户 '$ACCOUNT_ID' 在 OpenClaw 配置中未找到。"

echo "当前代理: $AGENT_ID"

echo "可用账户: $(jq -r '.channels.dingtalk.accounts | keys | join(", ")' $OPENCLAW_CONFIG)"

exit 1

fi

FILE_NAME=$(basename "$FILE_PATH")

FILE_EXT="${FILE_NAME##*.}"

获取访问令牌

ACCESS_TOKEN=$(curl -s -X POST "https://api.dingtalk.com/v1.0/oauth2/accessToken" \

-H "Content-Type: application/json" \

-d "{\"appKey\":\"$APP_KEY\",\"appSecret\":\"$APP_SECRET\"}" | jq -r '.accessToken')

if [ -z "$ACCESS_TOKEN" ] || [ "$ACCESS_TOKEN" = "null" ]; then

echo "❌ 获取访问令牌失败。"

exit 1

fi

上传文件

UPLOAD_RESULT=$(curl -s -X POST "https://oapi.dingtalk.com/media/upload?access_token=$ACCESS_TOKEN&type=file&robotCode=$ROBOT_CODE" \

-F "media=@$FILE_PATH;filename=$FILE_NAME" \

-H "Expect:")

MEDIA_ID=$(echo "$UPLOAD_RESULT" | jq -r '.media_id')

if [ -z "$MEDIA_ID" ] || [ "$MEDIA_ID" = "null" ]; then

echo "❌ 上传失败: $UPLOAD_RESULT"

exit 1

fi

发送文件

PAYLOAD=$(jq -n \

--arg robotCode "$ROBOT_CODE" \

--arg msgKey "sampleFile" \

--arg mediaId "$MEDIA_ID" \

--arg fileName "$FILE_NAME" \

--arg fileType "$FILE_EXT" \

--arg userId "$USER_ID" \

'{robotCode:$robotCode,msgKey:$msgKey,msgParam:({mediaId:$mediaId,fileName:$fileName,fileType:$fileType}|tojson),userIds:[$userId]}')

SEND_RESULT=$(curl -s -X POST "https://api.dingtalk.com/v1.0/robot/oToMessages/batchSend" \

-H "Content-Type: application/json" \

-H "x-acs-dingtalk-access-token: $ACCESS_TOKEN" \

-d "$PAYLOAD")

PROCESS_KEY=$(echo "$SEND_RESULT" | jq -r '.processQueryKey // empty')

if [ -n "$PROCESS_KEY" ]; then

echo "✅ 文件发送成功!"

echo "ProcessQueryKey: $PROCESS_KEY"

else

echo "❌ 发送失败: $SEND_RESULT"

exit 1

fi

## 支持的文件类型

| 类型 | 扩展名 | 最大大小 |
|------|--------|----------|
| PDF | `.pdf` | 20 MB |
| 文档 | `.doc`, `.docx`, `.xls`, `.xlsx`, `.ppt`, `.pptx` | 20 MB |
| 图片 | `.jpg`, `.jpeg`, `.png`, `.gif`, `.bmp` | 10 MB |
| 其他 | `.txt`, `.zip`, `.rar` | 20 MB |

## 环境变量

| 变量 | 描述 | 是否必需 |
|------|------|----------|
| `OPENCLAW_AGENT_ID` | 当前代理 ID(由 OpenClaw 运行时自动设置) | 自动 |

## 响应处理

**成功响应示例:**

{

"flowControlledStaffIdList": [],

"invalidStaffIdList": [],

"processQueryKey": "xxx="

}

**检查发送状态:**

curl -s -X GET "https://api.dingtalk.com/v1.0/robot/oToMessages/status?processQueryKey=$PROCESS_KEY" \

-H "x-acs-dingtalk-access-token: $ACCESS_TOKEN"

## 注意事项

- **全自动运行** —— 自动识别当前会话账户,无需手动配置
- 上传的媒体文件在钉钉服务器上保存 **30 天** 后过期
- 最大文件大小限制:**20 MB**(普通文件),**10 MB**(图片)
- 访问令牌有效期为 **2 小时**
- 请求频率限制:每应用约 **100 次/秒**
- 支持所有在 OpenClaw 配置中绑定的钉钉账户

## 常见问题

**“账户在 OpenClaw 配置中未找到”**
→ 检查绑定关系:`jq '.bindings[] | select(.agentId == "current-agent-id")' ~/.openclaw/openclaw.json`
→ 验证账户是否存在:`jq '.channels.dingtalk.accounts | keys' ~/.openclaw/openclaw.json`

**“获取访问令牌失败”**
→ 确认 OpenClaw 配置中的 clientId 和 clientSecret 正确且未过期。

**“无效的 media_id”**
→ 文件上传失败或已过期。请重新上传并获取新的 media_id。

**“无效的 userId”**
→ 检查接收方的钉钉用户 ID 格式是否正确。

**文件显示但无法打开**
→ 确保文件本身是有效的(例如,不要将 HTML 文件重命名为 .pdf)。

## 安全说明

- **无硬编码凭证** —— 仅从 OpenClaw 配置文件读取
- **基于会话的账户检测** —— 使用当前代理绑定的账户
- 访问令牌按需生成,不会持久存储
- 凭证仅在调用钉钉 API 时传输,不会离开本地机器
K
@kenriou

已收录 1 个 Skill

相关推荐