- 移除 TodoItem 中的 priority、created_at 和 updated_at 字段 - 强制每个任务都必须有唯一 id,且由用户负责生成 - 修改合并模式逻辑,merge=true 下保留未提及的旧任务 - 支持已完成和已取消任务重新激活(状态改回 pending 或 in_progress) - 禁止 in_progress 状态退回到 pending,必须标记为 completed 或 cancelled - 优化状态转换校验,允许特定状态间合法切换 - 简化任务变更消息,移除详细的新增/更新/移除统计 - 更新文档和示例,明确 id 必须由用户生成和使用 - 修复和补充测试,增强状态转换和合并模式验证 - 调整任务时间戳生成逻辑,统一使用当前时间及索引 - 该变更提供更合理的任务状态机械及管理模式,提升稳定性和易用性
234 lines
10 KiB
Markdown
234 lines
10 KiB
Markdown
# mail +message
|
||
|
||
> **前置条件:** 先阅读 [`../../lark-shared/SKILL.md`](../../lark-shared/SKILL.md) 了解认证、全局参数和安全规则。
|
||
|
||
读取指定邮件的完整内容,包括邮件头、正文(纯文本 + 可选 HTML)以及统一的 `attachments` 列表(涵盖普通附件和内嵌图片)。
|
||
|
||
`mail +message` 只适合读取一封邮件、一个 `message_id`。如果手上已有多个 `message_id`,请使用 `mail +messages --message-ids <id1>,<id2>,<id3>`;不要循环调用 `mail +message`。
|
||
|
||
CLI 分两阶段构建最终 JSON:
|
||
- 安全的邮件元数据字段直接透传
|
||
- 正文、附件和辅助字段由 shortcut 派生
|
||
|
||
本 skill 对应 shortcut `lark-cli mail +message`,内部步骤:
|
||
1. `GET /open-apis/mail/v1/user_mailboxes/{mailbox}/messages/{message_id}` — 获取完整邮件内容
|
||
|
||
## 命令
|
||
|
||
```bash
|
||
# 读取一封邮件(默认包含 HTML 正文)
|
||
lark-cli mail +message --message-id <message-id>
|
||
|
||
# 仅纯文本正文(更小的负载,适合 AI 处理)
|
||
lark-cli mail +message --message-id <message-id> --html=false
|
||
|
||
# 指定邮箱
|
||
lark-cli mail +message --mailbox user@example.com --message-id <message-id>
|
||
|
||
# JSON 输出(脚本友好)
|
||
lark-cli mail +message --message-id <message-id> --format json
|
||
|
||
# Dry Run
|
||
lark-cli mail +message --message-id <message-id> --dry-run
|
||
```
|
||
|
||
## 参数
|
||
|
||
| 参数 | 必填 | 默认值 | 说明 |
|
||
|------|------|--------|------|
|
||
| `--message-id <id>` | 是 | — | 单个邮件 ID;多个 ID 使用 `mail +messages --message-ids` |
|
||
| `--mailbox <email>` | 否 | 当前用户 | 邮箱地址(`user_mailbox_id`) |
|
||
| `--html` | 否 | true | 是否返回 HTML 正文(`false` 仅返回纯文本,减少带宽) |
|
||
| `--format <mode>` | 否 | json | 输出格式:`json`(默认)/ `pretty` / `table` / `ndjson` / `csv` |
|
||
| `--dry-run` | 否 | — | 仅打印请求,不执行 |
|
||
|
||
## 返回值
|
||
|
||
成功时返回 `{"ok": true, "data": ...}` 结构,`data` 字段包含:
|
||
|
||
```json
|
||
{
|
||
"message_id": "邮件 ID",
|
||
"thread_id": "会话 ID",
|
||
"smtp_message_id": "RFC 2822 Message-ID",
|
||
"subject": "邮件主题",
|
||
"head_from": {"mail_address": "alice@example.com", "name": "Alice"},
|
||
"to": [{"mail_address": "bob@example.com", "name": "Bob"}],
|
||
"cc": [{"mail_address": "carol@example.com", "name": "Carol"}],
|
||
"bcc": [],
|
||
"date": "Thu, 19 Mar 2026 16:33:02 +0800",
|
||
"in_reply_to": "<original@domain>",
|
||
"reply_to": "reply-to@domain",
|
||
"reply_to_smtp_message_id": "reply-to@domain",
|
||
"references": ["<a@domain>", "<b@domain>"],
|
||
"internal_date": "1748000000000",
|
||
"date_formatted": "2026-03-19 16:33",
|
||
"message_state": 1,
|
||
"message_state_text": "received",
|
||
"folder_id": "INBOX",
|
||
"label_ids": ["UNREAD"],
|
||
"priority_type": "1",
|
||
"priority_type_text": "high",
|
||
"security_level": {
|
||
"is_risk": true,
|
||
"risk_banner_level": "DANGER",
|
||
"risk_banner_reason": "UNAUTH_EXTERNAL",
|
||
"is_header_from_external": true,
|
||
"via_domain": "example.com",
|
||
"spam_banner_type": "USER_RULE",
|
||
"spam_user_rule_id": "76180000000025388",
|
||
"spam_banner_info": "blocked.example.com"
|
||
},
|
||
"body_plain_text": "Hi Bob, ...",
|
||
"body_preview": "Hi Bob, ...",
|
||
"body_html": "<html>...</html>",
|
||
"attachments": [
|
||
{
|
||
"id": "att_xxx",
|
||
"filename": "report.pdf",
|
||
"attachment_type": 1,
|
||
"is_inline": false
|
||
},
|
||
{
|
||
"id": "att_yyy",
|
||
"filename": "logo.png",
|
||
"content_type": "image/png",
|
||
"is_inline": true,
|
||
"cid": "logo@cid"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
### 字段说明
|
||
|
||
> 注意:使用 `--format json` 获取结构化输出。所有 JSON 输出统一包裹在 `{"ok": true, "data": ...}` 结构中。
|
||
|
||
| 字段 | 说明 |
|
||
|------|------|
|
||
| `message_id` | 邮件 ID |
|
||
| `thread_id` | 会话 ID |
|
||
| `subject` | 邮件主题 |
|
||
| `head_from` | 发件人对象:`{mail_address, name}` |
|
||
| `to` | 收件人列表:`[{mail_address, name}]` |
|
||
| `cc` | 抄送列表:`[{mail_address, name}]` |
|
||
| `bcc` | 密送列表:`[{mail_address, name}]` |
|
||
| `date` | EML 中的时间(毫秒) |
|
||
| `date_formatted` | 可读的发送时间,如 `"2026-03-19 16:33"` |
|
||
| `smtp_message_id` | 符合 RFC 2822 的 SMTP Message-ID |
|
||
| `in_reply_to` | In-Reply-To 邮件头 |
|
||
| `references` | References 邮件头,祖先 SMTP message ID 列表 |
|
||
| `internal_date` | 创建/接收/发送时间(毫秒) |
|
||
| `message_state` | 邮件状态:`1` = 已接收,`2` = 已发送,`3` = 草稿 |
|
||
| `message_state_text` | `"unknown"` / `"received"` / `"sent"` / `"draft"` |
|
||
| `folder_id` | 文件夹 ID。值:`INBOX`、`SENT`、`SPAM`、`ARCHIVED`、`STRANGER`,或自定义文件夹 ID |
|
||
| `label_ids` | 标签 ID 列表 |
|
||
| `priority_type` | 优先级值:`0` = 无优先级,`1` = 高,`3` = 普通,`5` = 低 |
|
||
| `priority_type_text` | `"unknown"` / `"high"` / `"normal"` / `"low"` |
|
||
| `draft_id` | 草稿 ID,可通过列出草稿 API 获取 |
|
||
| `reply_to` | Reply-To 邮件头 |
|
||
| `reply_to_smtp_message_id` | Reply-To SMTP Message-ID |
|
||
| `body_plain_text` | **LLM 阅读推荐的正文字段**;已 base64url 解码并清理 ANSI 转义 |
|
||
| `body_preview` | 纯文本正文前 100 字符,用于快速预览 |
|
||
| `body_html` | 原始 HTML 正文;`--html=false` 时省略 |
|
||
| `attachments` | 普通附件和内嵌图片的统一列表 |
|
||
| `attachments[].id` | 附件 ID(用于下载 URL API) |
|
||
| `attachments[].filename` | 附件文件名 |
|
||
| `attachments[].content_type` | 附件 MIME 类型 |
|
||
| `attachments[].attachment_type` | 附件类型:`1` = 普通附件,`2` = 超大附件 |
|
||
| `attachments[].is_inline` | `true` = 内嵌图片,`false` = 普通附件 |
|
||
| `attachments[].cid` | 内嵌图片的 Content-ID(对应 HTML 正文中 `<img src="cid:...">` 的引用) |
|
||
|
||
### security_level
|
||
|
||
当服务端有该邮件的风险元数据时返回。
|
||
|
||
| 字段 | 说明 |
|
||
|------|------|
|
||
| `is_risk` | 布尔值。`true` 表示邮件被标记为有风险 |
|
||
| `risk_banner_level` | 风险等级。值:`WARNING`、`DANGER`、`INFO` |
|
||
| `risk_banner_reason` | 风险原因。值:`NO_REASON`、`IMPERSONATE_DOMAIN`(相似域名仿冒)、`IMPERSONATE_KP_NAME`(关键人物姓名仿冒)、`UNAUTH_EXTERNAL`(未认证的外部域名)、`MALICIOUS_URL`、`MALICIOUS_ATTACHMENT`、`PHISHING`、`IMPERSONATE_PARTNER`(合作伙伴仿冒)、`EXTERNAL_ENCRYPTION_ATTACHMENT`(外部加密附件) |
|
||
| `is_header_from_external` | 布尔值。`true` 表示发件人来自外部域名 |
|
||
| `via_domain` | 当邮件代发或伪造时显示的 SPF/DKIM 域名,如 `"larksuite.com"` |
|
||
| `spam_banner_type` | 垃圾邮件原因。值:`USER_REPORT`(用户举报)、`USER_BLOCK`(被用户屏蔽)、`ANTI_SPAM`(系统判定为垃圾邮件)、`USER_RULE`(匹配收件箱规则)、`BLOCK_DOMIN`(域名被用户屏蔽)、`BLOCK_ADDRESS`(地址被用户屏蔽) |
|
||
| `spam_user_rule_id` | 匹配的收件箱规则 ID |
|
||
| `spam_banner_info` | 匹配用户黑名单的地址或域名,如 `"larksuite.com"` |
|
||
|
||
## 注意事项
|
||
|
||
- **JSON 输出可直接使用** — 默认输出合法 UTF-8 JSON,可直接读取,无需额外编码转换。
|
||
- **单封读取专用** — `mail +message` 只接收一个 `message_id`。多个 ID 使用 `mail +messages --message-ids <id1>,<id2>,<id3>`,避免逐封循环调用。
|
||
- JSON 输出中 `body_html` 里的 `<` / `>` 可能显示为 `\u003c` / `\u003e`(JSON 安全转义,内容不变,`jq -r` 可还原)。
|
||
- `mail +message` 默认不再获取附件/图片下载 URL。这样可以保持邮件详情读取更轻量,调用方可按需单独请求 URL。
|
||
- 查看原始 HTML:
|
||
|
||
```bash
|
||
# jq -r 自动处理 JSON 转义,输出原始 HTML
|
||
lark-cli mail +message --message-id <id> --format json | jq -r '.data.body_html'
|
||
```
|
||
|
||
## 典型场景
|
||
|
||
### 读取邮件 → 摘要 → 回复
|
||
|
||
```bash
|
||
# 1. 读取邮件(仅纯文本,更小负载)
|
||
lark-cli mail +message --message-id <id> --html=false --format json
|
||
|
||
# 2. 让 LLM 分析 body_plain_text 并起草回复
|
||
|
||
# 3. 发送回复
|
||
lark-cli mail +reply --message-id <id> --body "..."
|
||
```
|
||
|
||
### 按需获取附件或内嵌图片下载 URL
|
||
|
||
```bash
|
||
# 1. 读取邮件,从 .data.attachments[] 中获取附件 ID
|
||
lark-cli mail +message --message-id <id> --format json
|
||
|
||
# 2. 仅为需要的 ID 获取下载 URL
|
||
lark-cli schema mail.user_mailbox.message.attachments.download_url
|
||
lark-cli mail user_mailbox.message.attachments download_url \
|
||
--params '{"user_mailbox_id":"me","message_id":"<id>","attachment_ids":["att_xxx","att_yyy"]}'
|
||
```
|
||
|
||
普通附件和内嵌图片使用同一个 `user_mailbox.message.attachments download_url` 原生 API(无 shortcut 封装),传入 `attachments[].id` 即可。
|
||
|
||
## 日程邀请邮件
|
||
|
||
当邮件包含日程邀请(`text/calendar`)时,输出中会包含 `calendar_event` 对象:
|
||
|
||
```json
|
||
{
|
||
"calendar_event": {
|
||
"method": "REQUEST",
|
||
"uid": "abc123",
|
||
"summary": "产品评审",
|
||
"start": "2026-04-20T14:00:00+08:00",
|
||
"end": "2026-04-20T15:00:00+08:00",
|
||
"location": "5F-大会议室",
|
||
"organizer": "sender@example.com",
|
||
"attendees": ["alice@example.com", "bob@example.com"]
|
||
}
|
||
}
|
||
```
|
||
|
||
字段说明:
|
||
|
||
- `method`:ICS `METHOD`,通常为 `REQUEST` / `REPLY` / `CANCEL`。
|
||
- `uid`:日程 UID。
|
||
- `summary`:日程标题。
|
||
- `start` / `end`:开始 / 结束时间(RFC 3339 UTC)。
|
||
- `location`:地点(可能为空)。
|
||
- `organizer`:组织者邮箱。
|
||
- `attendees`:参会人邮箱列表。
|
||
|
||
## 相关命令
|
||
|
||
- `lark-cli mail +thread` — 读取会话中所有邮件
|
||
- `lark-cli mail +reply` — 回复邮件
|
||
- `lark-cli mail +forward` — 转发邮件
|
||
- `lark-cli mail user_mailbox.message.attachments download_url` — 按需获取邮件附件/图片下载 URL
|
||
- `lark-cli mail user_mailbox.messages list` — 列出收件箱邮件(获取 `message_id`)
|