home / skills / openclaw / skills / feishu-send-message

feishu-send-message skill

/skills/lycohana/feishu-send-message

This skill sends messages to Feishu users via API, auto-detecting phone or user IDs to ensure delivery across formats.

npx playbooks add skill openclaw/skills --skill feishu-send-message

Review the files below or copy the command above to add this skill to your agents.

Files (4)
SKILL.md
7.0 KB
---
name: feishu-send-message
description: |
  通过 API 向飞书用户发送消息。当你需要通过手机号或任意用户 ID(open_id、user_id、union_id)向飞书用户发送消息时使用。自动尝试所有 ID 类型以找到有效的那个。

  **新增**:消息长度指南和长内容多部分发送最佳实践!
---

# 飞书消息发送工具

单个工具 `feishu_send_message`,用于向飞书用户发送消息。

## ⚠️ 关键:正确用法

**这是一个 Python 脚本,不是 JSON 工具调用。**

### 命令行用法(正确):
```bash
python send_message.py <标识符> <消息>

# 示例:
python send_message.py "+8613560824490" "你好!"
python send_message.py "3b3ee7d1" "天气预报"
python send_message.py "ou_xxx" "你的消息"
```

### ❌ 错误(会失败):
```bash
python send_message.py --json-file message.json    # 不支持 --json-file!
python send_message.py --action send xxx           # 不支持 --action!
```

脚本接受**恰好 2 个位置参数**:
1. `identifier` - 手机号或用户 ID(open_id/user_id/union_id)
2. `message` - 要发送的文本消息

## 功能说明

1. 从 OpenClaw 配置读取飞书凭证
2. 自动获取 tenant_access_token
3. 支持多种用户 ID 格式(手机号、open_id、user_id、union_id)
4. 自动尝试所有可用的 ID 类型以找到有效的那个
5. 通过飞书 API 发送文本消息

## 支持的标识符格式

- **手机号**:`+8613560824490` 或 `13560824490`
- **open_id**:`ou_xxx`(当前应用中的用户 ID)
- **user_id**:`ou_xxx`(飞书中的企业用户 ID)
- **union_id**:`on_xxx`(跨应用的用户 ID)

**智能查找顺序**:
1. **本地配置优先**(`~/.openclaw/workspace/configs/feishu-users.json`)- 最快,无需 API 调用
2. **手机号查找** - 调用 API 获取所有 ID,然后尝试每个
3. **直接 ID** - 尝试该 ID,然后回退到其他类型

## 前置条件

从 `~/.openclaw/openclaw.json`:
- `appId`:飞书应用 ID(如 `cli_a98251e3d1f8900c`)
- `appSecret`:飞书应用密钥
- `domain`:(可选)API 域名 - `feishu`(中国版)或 `lark`(国际版)

首次查找后,用户 ID 会保存到 `~/.openclaw/workspace/configs/feishu-users.json`。

## API 端点

1. **获取 tenant_access_token**:
   ```
   POST https://open.{domain}/open-apis/auth/v3/tenant_access_token/internal
   ```

2. **通过手机号获取用户 ID**:
   ```
   POST https://open.{domain}/open-apis/contact/v3/users/batch_get_id
   ```

3. **发送消息**:
   ```
   POST https://open.{domain}/open-apis/im/v1/messages?receive_id_type={user_id|union_id|open_id}
   ```

## 消息类型

### 发送富文本消息(推荐 ✅)
用于格式化的消息。支持:
- ✅ 标题:`# 标题`
- ✅ 链接:`[文本](链接)`
- ✅ 表情符号:原样保留
- ✅ 换行:分隔段落
- ✅ 列表:`- 事项`

**示例**:
```bash
# 卡片格式 ✅
python send_message.py "+8613560824490" "# 🌤️ 天气通知

东莞天气预报

- 天气:多云 ☁️
- 气温:12-22℃

详情请查看 [天气预报](https://weather.com.cn)

祝你有美好的一天!"
```

### 发送纯文本消息
用于简单消息。支持:
- ✅ 换行(`\n`)
- ✅ 表情符号(🌤️ ☁️ 😊)

**示例**:
```bash
# 简单消息
python send_message.py "+8613560824490" "✅ 任务完成!
感谢你的使用~"
```

### 卡片格式支持的功能

| 功能 | 支持 |
|------|------|
| 标题 `#` | ✅ |
| 链接 `[文本](链接)` | ✅ |
| 表情符号 | ✅ |
| 换行 | ✅ |
| 列表 `-` | ✅ |
| **粗体** `**text**` | ❌ 不支持 |
| *斜体* `*text*` | ❌ 不支持 |
| 代码 `` `code` `` | ❌ 不支持 |

### 自动检测
脚本自动选择正确的格式:
- 当检测到 `# ` 或 `](` 时使用 `post` 格式
- 纯消息使用 `text` 格式

## 配置

无需额外配置 - 自动从 OpenClaw 配置读取。

## 错误处理

- **缺少凭证**:返回错误
- **无效标识符**:尝试检测并使用正确格式
- **API 错误**:自动尝试其他 ID 类型
- **最终失败**:返回带详细信息的错误

## 常见错误

| 错误 | 原因 | 解决方案 |
|------|------|----------|
| "id not exist" | 用户不在应用可见范围 | 将用户添加到应用的可见范围 |
| "invalid user_id" | ID 类型错误 | 改用手机号 |
| 权限被拒绝 | 缺少机器人权限 | 在飞书控制台添加 `im:message:send_as_bot` |
| `Invalid ids: [--json-file]` | 参数格式错误 | 使用位置参数:`python script.py <id> <msg>` |
| HTTP 400 + `example value is {ou_xxx}` | open_id 格式无效 | 确认 ID 是该应用正确的用户 ID |
| HTTP 400(无具体错误) | 消息过长 | 将内容拆分为多条消息 |

## 使用示例

**发送天气卡片格式消息**(推荐):
```bash
python send_message.py "+8613560824490" "# 🌤️ 东莞天气预报

更新于:2月7日 05:30

详细预报:
- 天气:多云 ☁️
- 气温:12℃ ~ 22℃
- 风力:无持续风向 <3级

小贴士:
早晚温差大,记得添衣哦~ 😊

查看详情 [天气预报](https://weather.com.cn)"
```

**发送简单消息**:
```bash
python send_message.py "+8613560824490" "你好,来自 OpenClaw!"
```

**发送带标题和链接的消息**:
```bash
python send_message.py "+8613560824490" "# 重要通知
这是标题内容
详见链接:[天气预报](https://weather.com.cn)"
```

**直接发送至 ID**:
```bash
python send_message.py "ou_9a013a756733f6910ebd9e3a1fe350fb" "你好!"
```

## ⚠️ 重要:消息长度限制

**飞书消息限制**:
- **文本消息**:无严格限制,但建议 < 5000 字符
- **富文本(post)**:建议总共 < 20000 字符
- **如果消息太长**:飞书 API 可能返回 HTTP 400 或截断

**长内容最佳实践**:

1. **拆分为多条消息**
   ```bash
   # 第1部分
   python send_message.py "3b3ee7d1" "# 报告 - 第1部分(共3部分)
   ...内容...
   (待续...)"

   # 第2部分(确认收到后)
   python send_message.py "3b3ee7d1" "# 报告 - 第2部分
   ...更多内容...
   (待续...)"
   ```

2. **使用文件作为内容来源**
   ```bash
   # 从文件读取(避免 CLI 参数问题)
   python send_message.py "3b3ee7d1" "$(cat long_message.txt)"
   ```

3. **发送前检查字符数**
   - 如果内容 > 3000 字符,考虑拆分
   - 使用 `wc -c` 或 `Measure-Object -Line` 检查长度

## 🐛 常见问题与解决方案

| 问题 | 原因 | 解决方案 |
|------|------|----------|
| 消息被截断 | 太长 | 拆分为多条消息 |
| 特殊字符错误 | CLI 引号问题 | 使用文件输入或更简单的文本 |
| "id not exist" | 用户不在应用可见范围 | 将用户添加到应用可见范围 |
| "invalid user_id" | ID 类型错误 | 改用手机号 |
| 权限被拒绝 | 缺少机器人权限 | 在飞书控制台添加 `im:message:send_as_bot` |
| HTTP 400 | 消息过长 | 拆分内容或减少格式 |

- `feishu.cn` - 中国版(默认)
- `larksuite.com` - 国际版

通过配置中的 `channels.feishu.domain` 或 `channels.feishu.accounts.main.domain` 设置。

Overview

This skill sends messages to Feishu/Lark users via the Feishu API using a phone number or any user identifier (open_id, user_id, union_id). It automatically attempts all supported ID types to find a valid recipient and reads credentials from OpenClaw configuration. The tool supports plain text and rich post-format messages and includes guidance for long content handling and multi-part sends.

How this skill works

The script reads app credentials from ~/.openclaw/openclaw.json, obtains a tenant_access_token, resolves the provided identifier (local cache first, then API lookup by phone or direct ID attempts), and posts the message to the correct endpoint. It auto-detects message format: uses post format when markdown-like patterns (# or ]() present) and text format otherwise. Successful lookups are cached in ~/.openclaw/workspace/configs/feishu-users.json for faster future sends.

When to use it

  • You need to message a Feishu/Lark user by phone number or any user ID (open_id/user_id/union_id).
  • You want automatic ID resolution so you don’t need to know which ID type is valid for your app.
  • You need to send formatted notifications (title, links, lists) or simple text messages.
  • You must send long content and want guidance for splitting into multiple parts or using file input.
  • You prefer a CLI Python tool that integrates with existing OpenClaw credentials.

Best practices

  • Pass exactly two positional arguments: identifier and message (do not use flags like --json-file).
  • Prefer rich post format for formatted content; include # for titles or [text](url) for links.
  • For long messages, split into multiple smaller messages (<3000 chars recommended for safe delivery; keep post content under ~20000 chars).
  • Cache lookups locally and update user visibility in Feishu if you see "id not exist" errors.
  • Use file input (cat long_message.txt) for complex or multi-line content to avoid shell quoting issues.

Example use cases

  • Send a weather card to a user by phone: python send_message.py "+8613560824490" "# 🌤️ Weather..."
  • Send a brief status update: python send_message.py "ou_9a013a..." "✅ Task completed!"
  • Deliver a long report in parts: split into Part 1/Part 2 and send sequentially, or stream via file: python send_message.py "3b3ee7d1" "$(cat long_message.txt)"
  • Resolve unknown ID types automatically when you only have a phone number and want to message via the bot.
  • Recover from invalid user_id errors by retrying with phone or union_id; use cache to avoid repeated lookups.

FAQ

What parameters does the script accept?

It accepts exactly two positional arguments: identifier (phone or ID) and message text. Flags like --json-file are not supported.

How do I handle messages that are too long?

Split into multiple messages (recommended if >3000 characters), or send content from a file. Rich post messages should be kept well under ~20000 characters to avoid API errors.

Why do I get "id not exist"?

The user may be outside the app's visible scope. Add the user to the app's visible range or message by phone so the tool can resolve a valid ID.