Files
market/skills/mail-operations/SKILL.zh-CN.md
Yige 74184056c4 fix(mail-operations): 按现行邮件服务路由修正技能文档(1.0.6) (#194)
## 背景 / Background

发票整理 Agent 在隔离开发实例里真机整理 QQ 邮箱时,按内置技能 `mail-operations` 的写法调用 IMAP
附件下载,拿到 400 `Missing required parameters`:技能写的请求体是 `{email, uid, folder,
partId}`,而 `POST /imap/attachment` 从 2026-03 创建起就只认 `{email, messageId,
attachmentId, folder?}`。顺着这一处,对照 desirecore origin/dev(`c1e2c5ac0`)的
`lib/mail-service/` 与 `MailOperations` 工具把整份技能逐条核对了一遍。

While a real-mailbox run of the invoice agent was downloading QQ Mail
attachments, the builtin `mail-operations` skill's IMAP attachment body
(`{email, uid, folder, partId}`) returned 400; the route has always
taken `{email, messageId, attachmentId, folder?}`. This PR re-audits the
whole skill against the current mail service routes.

## 改动 / Changes

共修正 27 处不一致:会直接导致调用失败 9 处、会误导能力判断 10 处、措辞 8 处。主要有:

- **调用入口**:改为 `MailOperations`(path 带 `/api`,capability
由工具注入);原文的固定端口、「无需认证」、`curl -k` 都不成立
- **附件**:body 字段更正;必须带 `save_to` 落盘(不带会被工具拒绝返回),回执给出路径、字节数、SHA-256
- **参数位置**:`messages/fetch`、`/sync`、IMAP 草稿发送的 `email`(以及 `/sync` 的
`provider`)放查询串;IMAP 草稿收件人是逗号分隔的 `to` / `cc`,更新草稿会换成新 uid
- **folder**:IMAP 单封操作要用 `GET /imap/folders` 返回的服务器路径,列表里的归一化值会 500
- **规则**:operator 是 `matches_regex`(未知 operator 恒为 false
且创建时不校验);`archive` / `move_to_folder` / `forward_to` / `star` 是空操作
- **搜索**:三个 provider 都支持,只查本地缓存、`q` 只匹配主题;Gmail 全文检索改用 `messages/fetch`
的 `query`
- **IMAP 仅收信账户**:`allowUnverifiedSmtp`、`smtp_verification_failed`、409
`smtp_unverified`、`verify-smtp`(失败也返回 200)
- **离线队列**:不会自动入队或处理,只改本地,`processed` 计数不代表执行
- 响应字段名(`toRecipients`、`bodyPreview` 等)、同步状态文件、`/imap/test` 返回形态等措辞修正
- 版本 1.0.6;新增 `market.required_client_version: 10.0.148` 与 sidecar
`compatibility.requiredClientVersion`——`MailOperations`(10.0.95)、`save_to`
与 Outlook/IMAP search(10.0.146)、`imap:<uid>` / fetch `offset` / folder
归一化(10.0.148)分版本上线,旧客户端按新文档操作会静默失败,门控让它们保留旧版

## 验证 / Verification

- 写补丁与审查由两个独立子代理完成:审查方对 9 处致命项全部、另外 13 处抽查逐条对照代码行,均成立;审查意见(最低客户端版本、IMAP
更新草稿换 uid、`/sync` 参数、Gmail 远程检索、`verify-smtp` 返回形态、离线队列计数、响应示例矛盾)已全部采纳
- 各项最低版本用 `git tag --contains` 对照发布 tag 复核
- `translate.py --check`:en-US human-locked 且 hash 新鲜(`source_hash` 按
`compute_source_hash` 重算)
- `validate-i18n`:0 error,123 warning(与 main 基线相同)
- `validate_catalog_metadata --require-complete`:0 error
- `git diff --check` 通过;新增行只有 `example.com` 占位地址,无真实邮箱、姓名、公司名或长数字编号

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-09-29 05:07:39 -04:00

23 KiB
Raw Blame History

mail-operations 技能

L0:一句话摘要

通过本地 REST API 收发邮件、搜索、标签管理和自动规则,支持 Gmail / Outlook / IMAP。

L1:概述与使用场景

能力描述

mail-operations 是一个流程型技能(Procedural Skill),通过 DesireCore 本地 REST API(由内置工具 MailOperations 调用)操作邮件系统。支持 Gmail(OAuth2)、Outlook(MSAL)和 IMAP/SMTP(QQ、163、Yahoo 等)三种邮箱类型,涵盖收发邮件、搜索、标签管理、附件下载、草稿管理和自动规则。

使用场景

  • 用户需要查看收件箱、发送或回复邮件
  • 用户需要搜索特定邮件或管理邮件标签/分类
  • 用户需要下载附件或管理草稿
  • 用户需要设置自动回复规则或触发智能体处理邮件

核心价值

  • 统一接口:三种邮箱通过统一 API 操作,降低使用复杂度
  • 本地安全:所有操作通过本地 API 完成,无需暴露凭证
  • 智能联动:支持自动规则和智能体邮件处理

L2:详细规范

如何进入邮箱服务

用户可通过以下路径进入邮箱管理界面:

  1. 点击左侧导航栏的第三个图标(文件夹图标)进入资源管理器
  2. 在资源管理器首页找到**「邮箱」**卡片,点击进入邮箱管理

如果用户不知道如何打开邮箱页面,引导他们按上述步骤操作即可。也可以在对话界面右上角点击「打开资源管理器」快捷入口,再选择邮箱卡片。


API 基础信息

  • 调用方式:使用内置工具 MailOperations,参数为 path(以 /api/ 开头的相对路径,查询参数直接拼在 path 里)、method(默认 GET)、body(JSON 对象)和 save_to(仅下载附件时使用,见第 6 节)。工具自动定位本机 Mail Service 并携带访问凭证,Agent 不需要、也不能自行提供 token。
  • 路径写法:下文端点均省略 /api 前缀,调用时要补上,例如 /imap/messages?email=me%40example.com&limit=20 对应 path: "/api/imap/messages?email=me%40example.com&limit=20"。唯一例外是健康检查 /ping(不带 /api)。
  • 不要直连端口:不要用 curl 访问 https://127.0.0.1:62000。端口从 62000 起动态分配(同时运行多个 DesireCore 实例时,62000 可能属于另一个实例),严格能力模式下不带凭证的直连请求一律返回 401。
  • 参数位置:GET / DELETE 的参数全部放查询串;POST / PUT 按下文表格区分查询串与 body。messages/fetch、标记已读/未读、Outlook 单封操作、IMAP 草稿发送等端点的 email 必须放在查询串,放进 body 会返回 400 Missing email parameter。/sync 的 provider 与 email 都必须放查询串:provider 放进 body 返回 400 Invalid provider,只有 email 放进 body 则不会报参数错误,但同步不会生效。
  • Content-Type: application/json(传 body 时工具自动设置)
  • 响应格式: 成功 {"code": 1, "msg": "Success", "result": ...},失败 {"code": 0, "msg": "错误信息"},部分错误另带稳定错误码字段 error(如 smtp_unverified)

强制行为规则

以下规则优先级最高,每次操作必须遵守。

规则 1:只能通过 MailOperations 工具操作

所有邮件操作必须且只能通过内置工具 MailOperations 调用本机 Mail Service 完成。禁止调用外部邮件客户端或浏览器,也不要用 curl / HttpRequest 直连本机端口(MailOperations 错误提示中明确给出的大附件流式落盘办法除外)。

如果返回 401,先按 msg 区分原因:

  1. Gmail / Outlook 返回 Not authorized 或 Authorization expired:告知用户该账户授权已失效,引导用户在 DesireCore 邮箱页面重新授权。如需代为发起,调用 Gmail POST /api/gmail/auth/initiate?loginHint={email} 或 Outlook POST /api/outlook/auth/initiate,把返回的 result.authUrl 交给用户在浏览器中打开(服务不会自动打开浏览器)
  2. IMAP 返回 Account not configured:账户未配置或配置已损坏,与授权过期无关,需要用户重新添加账户(先 /imap/test,再 /imap/accounts)
  3. 返回 error: "unauthorized"(缺少或无效的 Mail Service capability):说明请求没有经过 MailOperations,改用该工具重试

规则 2:操作前先确认账户

执行任何操作前,必须先调用 GET /api/accounts 获取账户列表:

  • 按邮箱地址或域名匹配用户指定的账户("QQ 邮箱"→ imap 中 qq.com)
  • 仅有一个账户且用户说"我的邮箱"→ 直接使用
  • 找不到匹配账户 → 告知用户并提示添加

规则 3:查询为空时自动同步

查询返回空列表或找不到指定数据时:

  1. 调用 POST /{provider}/messages/fetch?email={email} 同步远程数据(email 放查询串)
  2. 自动重试原查询
  3. 仍为空才告知用户

规则 4:写操作后提示刷新

发送、回复、删除、标记、标签变更等写操作成功后,提示:操作已完成。需要我帮你刷新当前邮箱页面以查看最新状态吗?


三种邮箱的差异速查

功能 Gmail Outlook IMAP
授权 OAuth2 OAuth2 (MSAL) 密码/授权码
Provider 路径 /gmail/ /outlook/ /imap/
邮件详情 路径参数 /{id} 查询参数 ?id={id} 路径参数 /{uid}(列表返回的 imap:<uid> 或纯数字 UID)+ ?folder=
搜索(本地缓存) 支持 支持 支持
远程同步翻页 pageToken(不支持 offset) skip / offset offset
草稿 支持(含列表/详情) 支持(创建/更新/删除/发送) 支持(创建/更新/删除/发送)
附件下载 支持 支持 支持
标签/分类 原生标签 Categories 仅本地标签
发信前提 已授权 已授权 SMTP 已验证(smtpStatus: verified)
自动规则 支持 支持 支持

核心操作

以下 {p} 代表 provider(gmail、outlook、imap),{email} 需 URL 编码(@ → %40,+ → %2B)。

1. 账户管理

操作 方法 端点
获取所有账户 GET /accounts
获取账户含设置 GET /accounts-with-settings
删除账户 DELETE /accounts/{p}/{email}
获取账户设置 GET /accounts/{p}/{email}/settings
更新账户设置 PUT /accounts/{p}/{email}/settings
更新显示名称 PUT /accounts/{p}/{email}/displayName — body: {"displayName": "..."}

IMAP 专属:

操作 方法 端点
获取预设邮箱配置 GET /imap/presets — 返回 QQ/163/Yahoo 等服务器配置
测试 IMAP 连接 POST /imap/test — body: {email, password, imap?: {host, port, secure}, smtp?: {host, port, secure}};域名在预设中时 imap / smtp 可省略。连接失败也返回 HTTP 200,须检查 result.imap.success 与 result.smtp.success
添加 IMAP 账户 POST /imap/accounts — body 同上,另可加 displayName、allowUnverifiedSmtp;成功返回 201 与 {email, smtpStatus, smtp}。SMTP 测试失败时默认返回 400(error: smtp_verification_failed),只有用户同意「仅收信」时才传 allowUnverifiedSmtp: true
重新验证 SMTP POST /imap/accounts/verify-smtp — body: {email};验证失败也返回 200,要看 result.smtp.success 与 result.smtpStatus:通过时 smtpStatus 恢复为 verified,失败时需要用户更新授权码后再验证

2. 邮件列表与同步

操作 方法 端点 参数
查询本地缓存 GET /{p}/messages 查询串:email, offset, limit, folder;返回 {messages, total, offset, limit}
远程同步 POST /{p}/messages/fetch?email= email 必须放查询串;body(或查询串):folder、limit(1–1000,默认 20);翻页:IMAP offset、Outlook skip / offset、Gmail pageToken(Gmail 传 offset 返回 400);返回 messages 与分页信息 pagination
手动触发同步 POST /sync?provider=&email= 参数放查询串;仅支持 gmail / outlook,IMAP 返回 400,请改用 messages/fetch

IMAP 远程同步较慢:每封邮件都要下载并解析完整内容(实测约 0.65 封/秒),单批 limit 建议不超过 100;更早的邮件用 offset(跳过最新的多少封)分批拉取。

folder 取值:

  • 本地缓存列表与搜索:inbox, sent, drafts, trash, spam, archive, other,大小写不敏感,也接受服务器原名(如 INBOX、Sent Messages);IMAP 的自定义文件夹在本地统一归为 other。
  • 远程同步:通用名(inbox、sent 等)会自动映射到 IMAP 实际文件夹、Outlook 文件夹或 Gmail 标签;IMAP 也可直接传 GET /imap/folders 返回的 path。Gmail 的 archive 没有对应标签,会不加过滤地拉取。
  • IMAP 单封操作(详情未命中缓存、标记已读/未读、删除、回复、附件下载)的 folder 会原样交给 IMAP 服务器,必须是 GET /imap/folders 返回的真实 path(如 INBOX、Sent Messages),省略时默认 INBOX。列表项里的 folder 是归一化后的值(如 sent),不能直接当作 IMAP 文件夹名。

响应格式(邮件列表项):

{
  "id": "消息ID(IMAP 为 imap:<uid>)", "provider": "gmail",
  "subject": "主题",
  "from": {"name": "...", "address": "..."},
  "toRecipients": [{"name": "...", "address": "..."}],
  "receivedDateTime": "ISO8601", "sentDateTime": "ISO8601",
  "bodyPreview": "摘要",
  "isRead": true, "hasAttachments": false,
  "folder": "inbox", "labelIds": ["INBOX"]
}

labelIds 只在 Gmail 邮件中出现,categories 只在 Outlook 邮件中出现。

3. 单封邮件操作

操作 Gmail Outlook IMAP
获取详情 GET /{id}?email= GET /message?id={id}&email= GET /{uid}?email=&folder=
标记已读 POST /{id}/read?email= POST /message/read?id={id}&email= POST /{uid}/read?email=&folder=
标记未读 POST /{id}/unread?email= POST /message/unread?id={id}&email= POST /{uid}/unread?email=&folder=
删除 DELETE /{id}?email= DELETE /message?id={id}&email= DELETE /{uid}?email=&folder=

所有路径前缀为 /api/{provider}/messages(Gmail/IMAP)或 /api/outlook/(Outlook 特殊路由)。IMAP 的 {uid} 可直接用列表返回的 id(imap:<uid>),folder 规则见第 2 节,INBOX 可省略。

邮件详情额外字段:body: {content, contentType}, ccRecipients, attachments: [{id, filename, contentType, size}]。IMAP 附件的 id 是附件在该邮件中的序号字符串("0"、"1"……)。

4. 发送与回复

发送新邮件 — POST /api/{p}/send:

{
  "email": "sender@example.com",
  "toRecipients": [{"name": "收件人", "address": "to@example.com"}],
  "ccRecipients": [],
  "bccRecipients": [],
  "subject": "主题",
  "body": "正文(支持 HTML)",
  "contentType": "html",
  "attachments": []
}

attachments 每项为 {filename, content(base64), contentType}。Gmail 要求至少一个非空收件人。IMAP 账户的 smtpStatus 为 unverified(仅收信接入)时,发送、回复、发送草稿均返回 409(error: smtp_unverified),需先引导用户重新验证 SMTP。

回复邮件:

Provider 端点 Body
Gmail POST /gmail/reply {email, messageId, body, contentType}
Outlook POST /outlook/message/reply?id={id}&email= {body, contentType}
IMAP POST /imap/reply {email, uid, folder, body, contentType}(uid 可用 imap:<uid>,folder 默认 INBOX)

5. 搜索(三种邮箱均支持)

GET /api/{p}/search?email={email}&q={keyword}({p} 为 gmail、outlook 或 imap)

搜索只查本地缓存,不访问邮件服务器;搜不到时先按规则 3 远程同步再搜。

参数 说明
q 关键词,只匹配主题(大小写不敏感)
from 发件人地址(包含匹配)
dateFrom / dateTo 日期范围 YYYY-MM-DD(按本机时区,含首尾两天)
hasAttachment true 时只返回带附件的邮件(false 不做筛选)
isUnread true 时只返回未读邮件(false 不做筛选)
folder 文件夹过滤,取值同本地缓存列表
offset / limit 分页,limit 最大 200

参数名必须完全一致,未知参数(如 query、hasAttachments)直接返回 400。返回 {messages, total, offset, limit}。

需要按正文或发件人在 Gmail 服务器上全文检索时,改用 POST /gmail/messages/fetch?email= 的 query 参数:它原样交给 Gmail API,支持 Gmail 搜索语法(如 from:、has:attachment),结果同时写入本地缓存。Outlook 与 IMAP 没有对应的远程检索参数。较旧的客户端若对 /outlook/search 或 /imap/search 返回 404,改为分页读取 GET /{p}/messages 后自行筛选。

6. 附件下载

Provider 方法 端点 Body
Gmail POST /gmail/messages/{messageId}/attachment {email, attachmentId}
Outlook POST /outlook/attachment {email, messageId, attachmentId}
IMAP POST /imap/attachment {email, messageId, attachmentId, folder?}
  • attachmentId 取自邮件详情的 attachments[].id,先调用详情接口拿到附件列表。
  • IMAP:messageId 直接用列表返回的 id(如 imap:12345);attachmentId 是附件序号字符串(第一个附件为 "0");folder 为服务器上的真实文件夹路径,INBOX 可省略。
  • 下载附件时必须给 MailOperations 传 save_to(目标文件路径):工具在进程内完成 base64 解码并写入文件,只返回绝对路径、字节数与 SHA-256;不传 save_to 时附件响应会被工具拒绝返回。目标路径须位于允许写入的工作目录内。
  • 端点原始响应为 result: {data: <base64>, size};响应超过约 32MB 时工具会拒绝解析,此时按工具错误提示中的流式落盘办法处理,或请用户在邮箱页面手工导出附件。

示例(IMAP):

{
  "path": "/api/imap/attachment",
  "method": "POST",
  "body": {"email": "me@example.com", "messageId": "imap:12345", "attachmentId": "0"},
  "save_to": "./attachments/report.pdf"
}

Gmail 使用 POST 因为 attachmentId 可能超出 URL 长度限制。

7. 草稿管理

Gmail:

操作 方法 端点
获取草稿列表 GET /gmail/drafts?email=&limit=
获取草稿详情 GET /gmail/drafts/{draftId}?email=
创建草稿 POST /gmail/drafts — body: {email, to, cc, subject, body, contentType}(to / cc 是逗号分隔的地址字符串)
更新草稿 PUT /gmail/drafts/{draftId} — body 同创建
删除草稿 DELETE /gmail/drafts/{draftId}?email=

Outlook:

操作 方法 端点
创建草稿 POST /outlook/drafts — body: {email, toRecipients, subject, body, contentType}
更新草稿 PUT /outlook/drafts?id={draftId}&email= — body 同创建
删除草稿 DELETE /outlook/drafts?id={draftId}&email=
发送草稿 POST /outlook/drafts/send?id={draftId}&email=

IMAP:

操作 方法 端点
创建草稿 POST /imap/drafts — body: {email, to, cc, subject, body, contentType}(to / cc 是逗号分隔的地址字符串,不是 toRecipients 数组);返回 {uid, id}
更新草稿 PUT /imap/drafts/{uid} — body 同创建;实现是删掉旧草稿再新建,返回新的 {uid, id},之后发送或删除要用新 uid(拿旧 uid 会得到 404 Draft not found)。服务器不支持 UIDPLUS 时返回的 uid 为 0,此时先重新读取草稿列表再操作
删除草稿 DELETE /imap/drafts/{uid}?email=
发送草稿 POST /imap/drafts/{uid}/send?email= — email 放查询串,无需 body

8. 标签管理(统一接口)

操作 方法 端点
获取标签列表 GET /labels?provider=&email=
获取单个标签 GET /labels/{labelId}
创建标签 POST /labels — body: {name, color, provider, email, visible}
更新标签 PUT /labels/{labelId} — body: {name, color, order, visible}
删除标签 DELETE /labels/{labelId}
获取邮件标签 GET /mails/{p}/{email}/labels?mailId=
添加邮件标签 POST /mails/{p}/{email}/labels?mailId= — body: {"labelId": "..."}
批量设置标签 PUT /mails/{p}/{email}/labels?mailId= — body: {"labelIds": [...]}
移除邮件标签 DELETE /mails/{p}/{email}/labels?mailId=&labelId=
获取标签下邮件 GET /labels/{labelId}/mails?provider=&email=&limit=&offset= — 返回 mailIds(不含邮件内容)

统一标签接口只修改 DesireCore 本地数据,不会同步到邮件服务器。需要改动服务器侧标签时,使用下方 Gmail 原生标签或第 9 节 Outlook 分类。

Gmail 原生标签:

  • 获取标签列表:GET /api/gmail/labels?email=
  • 修改邮件标签:POST /api/gmail/messages/{id}/labels — body: {email, addLabelIds, removeLabelIds}
  • 同步远程标签:POST /api/gmail/labels/sync?email=

9. Outlook 分类

Outlook 使用 Categories 而非 Labels。

操作 方法 端点
获取分类 GET /outlook/categories?email=
同步分类 POST /outlook/categories/sync?email=
创建分类 POST /outlook/categories/create?email= — body: {displayName, color}
更新分类 PUT /outlook/categories/update?email=&categoryId= — body: {displayName, color}
删除分类 DELETE /outlook/categories/delete?email=&categoryId=
修改邮件分类 POST /outlook/message/categories?id=&email= — body: {addCategories, removeCategories}

color 使用 Outlook 预设值 preset0 ~ preset24。

10. 自动规则

操作 方法 端点
获取所有规则 GET /rules?provider=&email=
获取单个规则 GET /rules/{ruleId}
创建规则 POST /rules
更新规则 PUT /rules/{ruleId}
删除规则 DELETE /rules/{ruleId}
启用/禁用 POST /rules/{ruleId}/toggle
对邮件执行规则 POST /rules/execute — body: {provider, email, mailId}
测试规则匹配 POST /rules/{ruleId}/test — body 同上

创建规则 body:

{
  "name": "规则名",
  "description": "说明",
  "provider": "gmail",
  "email": "xxx@gmail.com",
  "enabled": true,
  "conditions": [
    {"field": "from|to|subject|body|has_attachment", "operator": "contains|not_contains|equals|not_equals|starts_with|ends_with|matches_regex|is_true|is_false", "value": "..."}
  ],
  "conditionLogic": "and",
  "actions": [
    {"type": "add_label|remove_label|mark_as_read|mark_as_unread|delete|auto_reply|agent_handle", "value": "..."}
  ],
  "priority": 1,
  "stopOnMatch": false
}

正则条件的 operator 是 matches_regex(写成 regex 会被当作未知操作符,永远不匹配);is_true / is_false 只用于 has_attachment。

动作类型说明:

type value 说明
add_label 标签 ID 添加本地标签
remove_label 标签 ID 移除本地标签
mark_as_read 省略 仅在本地缓存中标记已读
mark_as_unread 省略 仅在本地缓存中标记未读
delete 省略 仅从本地缓存删除,服务器上的邮件不受影响
auto_reply 回复文本 自动回复固定内容
agent_handle Agent ID 触发智能体处理邮件

规则在轮询引擎检测到新邮件时自动执行,无需手动调用(IMAP 只覆盖收件箱的新邮件)。auto_reply 和 agent_handle 支持全部三种邮箱类型;agent_handle 在创建或更新规则时绑定当时的 Agent Service 连接。archive、move_to_folder、forward_to、star 可以保存,但当前执行时不做任何操作,不要向用户承诺这些效果。

11. 授权管理

操作 方法 端点
Gmail OAuth POST /gmail/auth/initiate?loginHint={email} — 返回 result.authUrl,由用户在浏览器中打开完成授权
Gmail 状态 GET /gmail/auth/status?email=
Outlook OAuth POST /outlook/auth/initiate — 返回 result.authUrl,由用户在浏览器中打开完成授权
Outlook 状态 GET /outlook/auth/status?email=

12. 文件夹

操作 方法 端点
IMAP 文件夹列表 GET /imap/folders?email= — 返回 [{name, path, specialUse, flags}],IMAP 单封操作的 folder 使用其中的 path
Outlook 文件夹列表 GET /outlook/folders?email=

Gmail 文件夹固定:inbox, sent, drafts, trash, spam, archive。


数据同步机制

邮件系统采用本地缓存 + 定期轮询:

  • 写操作(发送、标记、删除、Gmail 原生标签、Outlook 分类):通过对应 provider 端点同时更新本地和远程,无延迟;统一标签接口(第 8 节)和自动规则中的标记、删除、标签动作只修改本地
  • 读操作(查询、搜索):返回本地缓存,可能有延迟(默认 30 秒轮询)
  • 远程变更(用户在官方页面操作):Gmail / Outlook 需等待下次轮询同步;IMAP 轮询只拉取收件箱的新邮件,其他文件夹需主动调用 messages/fetch,服务器上对已缓存邮件做的已读、删除等变更不会回写到本地

存储路径:${DESIRECORE_ROOT}/mail/{provider}/{email}/(meta.json, index.json, messages/)


错误处理

状态码 原因 处理
400 参数错误(包括参数放错位置,如把查询串参数放进 body) 按 msg 检查参数名与位置
401 Gmail/Outlook 授权失效、IMAP 账户未配置,或缺少 Mail Service capability 按规则 1 处理,不要尝试其他途径
404 资源不存在 先同步再重试(规则 3)
409 IMAP 账户 SMTP 未验证(error: smtp_unverified) 引导用户重新验证 SMTP(POST /imap/accounts/verify-smtp)
500 内部错误(IMAP 常见原因:folder 不是服务器上存在的文件夹) 先检查 folder,仍失败则告知用户稍后重试

IMAP 注意:国内邮箱(QQ、163)需使用"授权码"而非登录密码。用 /imap/test 预先验证配置,并检查返回的 result.imap.success 与 result.smtp.success。