Files
wmailhub/docs/API.md
T

13 KiB

WmailHub API 文档

适用版本:v2.9.0(版本号以 /api/health 返回为准)。Base URL:生产 https://wmailhub.adx9.com,本地开发 http://127.0.0.1:18787。

目录


认证方式

三套通道并存,按端点区分:

通道 适用端点 凭据
Cookie 会话 /api/auth/*、/api/*(Console Web)、/api/admin/*、/api/settings/*、/api/oauth/* 登录后 wmh_session Cookie(HttpOnly,7 天)
Bearer Key /api/v1/*(含 /api/v1/mcp) Authorization: Bearer wmh_…(32 位;API 与 MCP 共用同一 Key)
HMAC 签名 /internal/* Email Worker 专用,见 docs/04 / docs/11
  • Key 在 设置 → 全局 Webhook → API / MCP Key 生成/轮换/撤销;明文仅生成时返回一次,服务端只存 SHA-256;新 Key 生成后旧 Key 立即失效。
  • Cookie 会话的写请求有 CSRF 防护:带 Cookie 时 Origin/Referer 必须与站点 Host 一致,否则 403。Bearer Key 调用不受影响。

健康检查与探测

GET /api/health

公开。返回 { ok: true, name: "WmailHub", version: "2.9.0" }。

GET /auth/status

公开。统一登录探测:返回 { enabled: boolean, issuer: string | null },登录页据此显示「ZITADEL 统一登录」按钮。

登录会话 API(/api/auth)

POST /api/auth/login

{ "username": "admin", "password": "admin" }

成功 200 { ok: true, user: { id, username } } 并下发会话 Cookie;失败 401 {"error":"invalid username or password"}。默认账号 admin / admin(首次启动自动播种)。

POST /api/auth/logout

清除会话 Cookie,返回 { ok: true }。(ZITADEL 登录的用户同样只清本地会话,IdP 侧 SSO 会话保留。)

GET /api/auth/me

返回当前用户 { user: { id, username }, now };未登录 401。用户名以库内实时数据为准。

ZITADEL 统一登录(/auth)

OIDC Authorization Code + PKCE(无 client secret),与密码登录双通道并存;单用户系统——统一登录成功即登录本平台唯一账号(没有权限设置)。配置入口:设置 → ZITADEL 统一登录(issuer + client_id;回调地址 {origin}/auth/callback 需登记到 ZITADEL 应用)。详细设计见 docs/12。

端点 说明
GET /auth/login 发起授权,302 到 IdP;可选 ?return=/<站内路径> 指定回跳(默认 /)。未启用 302 → /login?error=oidc_disabled
GET /auth/callback IdP 回调(浏览器重定向,无需调用):一次性 state 校验 → 换码 → userinfo → 登录唯一用户 → 下发会话 Cookie → 302 回站内;失败 302 → /login?error=<code>

错误码:oidc_disabled / oidc_unavailable / state_invalid / oidc_exchange_failed。

Console Web API(/api/*,Cookie 会话)

以下端点未登录一律 401。分页参数统一 limit(默认 20,最大 100)与 offset,列表返回 { items, total }。

Cloudflare 账号 /api/accounts

方法与路径 说明
GET /api/accounts 账号列表
GET /api/accounts/:id 账号详情(接入步骤、OAuth 连接、域名、Worker 凭据)
PATCH /api/accounts/:id 改名 { name }
DELETE /api/accounts/:id 删除账号(级联清理 Cloudflare 侧 Email Routing/Worker,尽力而为)
POST /api/accounts/batch-delete 批量删除 { ids: string[] } → { ok, deleted, failed[] }
POST /api/accounts/token API Token 接入 { name, token }(后端先探 Cloudflare 再接入)→ { ok, account_id }
POST /api/accounts/:id/rotate 轮换 Worker 凭据;secret 仅本次返回,已配域名自动重部署
GET /api/accounts/:id/worker-secret 本地/运维:读取当前 Worker credential

域名 /api/domains

方法与路径 说明
GET /api/domains 域名列表(含各域名 Webhook 配置与邮箱计数)
GET /api/domains/filters/accounts 账号筛选项
POST /api/domains/:id/setup 配置 Email Workers(部署 Worker + 开 Routing + catch-all)→ { ok, error? }
PUT /api/domains/:id/webhook 域名级 Webhook { url, headers?, key? }(url 空串清除;key undefined 保留、空格清除)
DELETE /api/domains/:id/webhook 清除域名级 Webhook
DELETE /api/domains/:id / POST /api/domains/batch-delete 删除(级联邮箱与邮件)

邮箱 /api/mailboxes

方法与路径 说明
GET /api/mailboxes?domain_id= 邮箱列表
POST /api/mailboxes 创建 { domain_id, address, retention_seconds?, catch_all? } → { ok, id, address };重名 409
PATCH /api/mailboxes/:id { status?: "active"|"disabled", retention_seconds?: number|null }(null=回到全局默认 86400 秒)
PUT /api/mailboxes/:id/webhook 邮箱级 Webhook,语义同域名级
DELETE /api/mailboxes/:id/webhook 清除邮箱级 Webhook
DELETE /api/mailboxes/:id / POST /api/mailboxes/batch-delete 删除

Webhook 生效顺序:邮箱 → 域名 → 全局,取第一个已配置的。

邮件 /api/emails

方法与路径 说明
GET /api/emails?domain_id=&mailbox_id=&q=&limit=&offset= 列表(仅未过期)
GET /api/emails/:id 详情(正文 text/html/markdown + 附件列表);过期 410
GET /api/emails/:id/attachments/:attId 下载附件
GET /api/emails/:id/raw 原始 EML
DELETE /api/emails/:id / POST /api/emails/batch-delete 删除
POST /api/emails/retain 保留 { ids }(永不过期,Cron 跳过)→ { ok, retained }

操作日志 /api/logs

GET /api/logs?target_type=&action=&q=&limit=&offset=。target_type ∈ account/domain/mailbox/email/webhook/user/settings;库里最多保留 10000 条。

设置 /api/settings

方法与路径 说明
GET /api/settings 全量读取:当前用户名、全局 Webhook(key 只回 last4)、API Key 元信息、Cloudflare OAuth、ZITADEL 统一登录(含回调地址与上次统一登录身份)
PUT /api/settings 保存 { webhook?, cf_oauth?, oidc? };webhook.key/cf_oauth.secret:undefined 保留、空串清除、非空设置;oidc: { issuer, client_id, enabled? }(enabled 缺省沿用已存值)
PUT /api/settings/password 改密码 { old_password, new_password }(≥6 位)
PUT /api/settings/username 改用户名 { new_username, password }(需当前密码;2-32 位字母/数字/_ . -;成功重签会话 Cookie;重名 409)
POST /api/settings/api-key 生成(轮换)API/MCP Key → 201 { key, created_at }(明文仅此一次)
DELETE /api/settings/api-key 撤销并删除 Key
DELETE /api/settings/cf-oauth 清除 Cloudflare OAuth 凭据(env 兜底仍可用)
DELETE /api/settings/oidc 清除统一登录配置(已建立的绑定保留)

Cloudflare OAuth /api/oauth

方法与路径 说明
GET /api/oauth/mode `{ mode: "cloudflare"
GET /api/oauth/cloudflare/start 生成一次性 state,返回 { url, state }(浏览器跳 url 完成授权)
GET /api/oauth/cloudflare/callback 授权回调(浏览器重定向,无需调用)
GET /api/oauth/cloudflare/preflight 授权配置自检(探测 Cloudflare 授权端点 + scope 探测)
GET /api/oauth/connections 已建立的 OAuth 连接(不含 token)

管理 /api/admin

GET /api/admin/version;GET /api/admin/stats(Dashboard 统计 + 最近 8 封邮件);POST /api/admin/cron/run(手动触发 TTL 清理与 Webhook 投递)。

开放 API(/api/v1/*,Bearer Key)

认证:Authorization: Bearer wmh_…;无 Key/Key 无效 401。所有邮件读取强制只返回未过期邮件。

GET /api/v1/accounts

{ items: [{ id, name, cloudflare_account_id, worker_id, status, created_at }] }

GET /api/v1/domains

{ items: [{ id, name, status, account_id, created_at }] }

GET /api/v1/mailboxes

{ items: [{ id, address, status, is_catch_all, retention_seconds, domain_id, domain_name }] }

POST /api/v1/mailboxes

{ "domain_id": "dom_xxx", "address": "hello", "retention_seconds": 86400, "webhook": "https://hooks.example.com/wmail" }
  • domain_id 可省略(v2.8.0 起):随机分配一个已启用 Email Workers 的域名;此时 address 必须为本地部分(不带 @)。
  • webhook 可选(v2.8.0 起):创建时直接配置邮箱级 Webhook(先校验再建邮箱,校验失败不留半截数据;SSRF 规则同 Console——拒绝私网/localhost/元数据地址)。
  • 返回 201 { ok: true, id, address, webhook? };错误:400 address required / 404 domain not found / 409 mailbox already exists / 409 no available domain (none has Email Workers enabled)。

DELETE /api/v1/mailboxes/:id

成功 { ok: true };不存在 404。

GET /api/v1/emails?mailbox_id=&limit=&offset=

{ items: [{ id, mailbox_id, mailbox_address, message_id, from_address, to_addresses, subject, size, received_at, expires_at }] }(仅未过期)。

GET /api/v1/emails/:id

{ email: { …全字段含 text_body/html_body/markdown_body }, attachments: [{ id, filename, content_type, size, content_id }] };不存在 404,已过期 410 {"error":"email expired"}。

curl 示例

KEY="wmh_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
BASE="https://wmailhub.adx9.com"

# 随机域名建邮箱 + 邮箱级 Webhook
curl -s -X POST "$BASE/api/v1/mailboxes" \
  -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
  -d '{"address":"hello","webhook":"https://hooks.example.com/wmail"}'

# 拉最近邮件(取第一条详情)
curl -s -H "Authorization: Bearer $KEY" "$BASE/api/v1/emails?limit=1"

MCP(/api/v1/mcp)

Streamable HTTP(JSON-RPC 2.0,协议版本 2025-06-18),仅 POST(GET → 405),Bearer Key 与 API 共用。方法:initialize → notifications/initialized → tools/list / tools/call;ping 可用。

MCP 客户端配置:

{
  "mcpServers": {
    "wmailhub": {
      "type": "http",
      "url": "https://wmailhub.adx9.com/api/v1/mcp",
      "headers": { "Authorization": "Bearer wmh_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" }
    }
  }
}

工具清单(v2.9.0 共 6 个)

工具 参数 说明
list_domains — 列出可用域名(创建邮箱的 domain_id 由此获取)
list_mailboxes — 列出邮箱(含域名与保留策略)
list_emails mailbox_id?, limit? 列出未过期邮件(按收到时间倒序)
get_email email_id 邮件详情(正文 + 附件);过期返回资源错误 -32002
create_mailbox address, domain_id?, retention_seconds?, webhook? 创建邮箱;domain_id 省略时随机分配(此时 address 须为本地部分);webhook 为可选邮箱级 Webhook URL
delete_mailbox mailbox_id 删除邮箱

错误约定:-32601 未知方法/工具、-32602 参数错误、-32002 资源不存在(如邮件过期)。

Webhook(收件推送)

收到邮件时按 邮箱 → 域名 → 全局 取第一个已配置的 Webhook 入队投递。Payload:

{
  "event": "email.received",
  "id": "msg_xxx",
  "mailbox": "hello@example.com",
  "from": "user@example.org",
  "to": ["hello@example.com"],
  "subject": "Hello",
  "text": "Hello World",
  "markdown": "Hello **World**",
  "received_at": "2026-09-30T10:00:00Z"
}

请求头:X-WmailHub-Event、X-WmailHub-Delivery、X-WmailHub-Timestamp、X-WmailHub-Signature(签名 = HMAC-SHA256(key, "<timestamp>.<body>"),配了 key 才有);配置 key 时默认携带 Authorization: Bearer <key>,自定义头优先。2xx 为成功;5xx/超时按指数退避重试,耗尽后置 exhausted;Cron 周期性重投 pending/failed。

内部 API(/internal,Email Worker 专用)

POST /internal/email/authorize 与 POST /internal/email/ingest:Email Worker 取收件凭据与投递邮件,HMAC 签名认证,协议见 docs/04 与 docs/11,不对外暴露。

错误码约定

状态码 场景
400 参数缺失/非法(webhook URL 不合法、用户名格式错误等)
401 未登录 / Bearer Key 缺失或无效
403 CSRF 校验失败(带 Cookie 的跨源写请求)
404 资源不存在
409 冲突(邮箱已存在、无可用域名、用户名已存在)
410 邮件已过期(Gone)
503 依赖未配置(如 Cloudflare OAuth 未配置时添加账号)

错误响应统一为 {"error": "<中文或英文消息>"}。