文档

基于 MCPEmails 构建

MCP 客户端能做的一切,脚本都能用普通 HTTPS 完成。一个端点,一个 API 密钥,JSON 进,JSON 出。本指南涵盖身份验证、你需要的三个调用、错误、重试、限制,以及新邮件的 webhook。

端点

每个请求都是发往 https://mcpemails.com/api/mcp 的 JSON-RPC 2.0 POST。这与 claude.ai、ChatGPT 和其他 MCP 客户端使用的是同一个端点,工具相同,权限相同,所以脚本和聊天助手看到的是同一个产品。

  • 发送 Content-Type: application/json 和 Accept: application/json。响应是一个 JSON 对象。
  • 服务器不保存会话。没有需要打开或关闭的东西,每个请求都带自己的 Authorization 头。
  • 成功的工具结果带有类型化的 structuredContent 对象,你不必解析自然语言。同样的数据也以 JSON 字符串形式放在 content[0].text 中。

身份验证

API 密钥

  • 在控制台的 API 密钥 → 新建密钥 中创建密钥。按将要使用它的脚本或工作流命名。
  • 密钥是 mcpe_ 加 64 个十六进制字符。它只在创建时显示一次,之后只保存哈希。请当场复制;丢失的密钥无法找回,只能替换。
  • 每次请求都以 Authorization: Bearer mcpe_... 的形式发送。切勿把密钥放进 URL 或查询字符串。
  • 每个套餐都可以创建任意数量的密钥。每个脚本或工作流用一个密钥,这样撤销一个不会影响其他的。
  • 在 API 密钥 页面撤销密钥会立即终止访问。

权限范围

每个密钥只拥有你在创建时勾选的权限。之后可以通过 编辑访问权限 修改,改动在下一次调用时生效,无需重新连接。

权限范围允许的操作
read:email列出、阅读和搜索邮件,下载附件,列出收件箱和文件夹。
search:email为旧密钥保留。搜索已由 read:email 覆盖。
send:email发送、回复和转发。
manage:drafts创建、更新和删除草稿。发送草稿还需要 send:email。
manage:folders移动、复制、标记和归档邮件;创建、重命名和删除文件夹。
delete:email删除和批量删除邮件。
manage:contacts从最近的邮件中搜索联系人。
schedule:email定时发送以及管理已定时的邮件。
manage:automations创建按计划运行、无需有人看管的规则。

从 read:email 开始,只在工作流确实需要时再添加写入权限。超出密钥权限范围的调用会在我们联系你的邮件服务器之前被拒绝。工作区中的查看者只能持有读取权限。

收件箱访问

默认情况下,密钥可以访问工作区中的所有收件箱。要把它限定在其中几个,请在密钥上打开 编辑访问权限,在 收件箱访问 下选择收件箱。这一限制在每次调用时都会检查,所以限定在支持收件箱的密钥读不到财务收件箱,无论请求怎么写。

连接器应用的 OAuth

由用户自行连接的应用,例如 claude.ai、ChatGPT 和其他 MCP 客户端,使用 OAuth 而不是密钥登录:动态客户端注册、带 PKCE 的授权码,以及一个由用户选择权限范围和收件箱的授权页面。参见 OAuth 连接。对于你自己的脚本、服务器和工作流,API 密钥更简单。

三个调用

1. initialize(可选)

MCP 客户端以 initialize 开始。脚本可以跳过它,因为服务器不保存会话,但它是检查密钥是否可用、读取服务器说明的低成本方式。

bash
curl -s https://mcpemails.com/api/mcp \
  -H "Authorization: Bearer $MCPEMAILS_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "initialize",
    "params": {
      "protocolVersion": "2025-06-18",
      "clientInfo": { "name": "my-agent", "version": "1.0" },
      "capabilities": {}
    }
  }'

2. tools/list

tools/list 返回该密钥可以调用的每个工具,包括描述、输入 schema 和输出 schema。请在启动时读取它,而不是硬编码工具名或参数:列表按密钥的权限范围过滤,而且工具会随时间增加参数。

bash
curl -s https://mcpemails.com/api/mcp \
  -H "Authorization: Bearer $MCPEMAILS_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{ "jsonrpc": "2.0", "id": 2, "method": "tools/list" }'

3. tools/call

按名称调用工具并传入参数。大多数工具接受一个 action 来决定做什么,例如 email_read 上的 list、read 或 search。用 inbox(邮箱地址)或 inbox_id 指定邮箱;inbox_list 会同时返回两者。

bash
curl -s https://mcpemails.com/api/mcp \
  -H "Authorization: Bearer $MCPEMAILS_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 3,
    "method": "tools/call",
    "params": {
      "name": "email_read",
      "arguments": { "action": "list", "inbox": "you@example.com", "unread": true, "limit": 20 }
    }
  }'

一个成功的结果:

JSON
{
  "jsonrpc": "2.0",
  "id": 3,
  "result": {
    "content": [{ "type": "text", "text": "{\"messages\":[...],\"total\":42, ...}" }],
    "structuredContent": {
      "messages": [{ "id": "...", "subject": "...", "from": { "name": "...", "email": "..." } }],
      "total": 42,
      "total_is_estimate": false,
      "has_more": true,
      "next_offset": 20
    }
  }
}

工具参考 介绍每个工具,curl 指南 有更多示例。

错误

错误有两类。完全无法执行的请求以带 HTTP 状态码的 JSON-RPC error 返回。到达了工具但被工具拒绝的请求以普通 result 返回,并带 isError: true,这样 AI 模型可以读到原因。请根据 data.error_code 或 _meta 中的代码分支,不要依赖消息文本。

响应何时出现如何处理
HTTP 401, -32001密钥缺失、格式错误、已撤销或已过期。修正 Authorization 头或创建新密钥。重试没有用。
HTTP 403, -32004, insufficient_scope密钥缺少此工具操作所需的权限范围。data.required_scopes 列出了可以放行的权限。通过 编辑访问权限 添加该权限范围,或换用另一个密钥。
HTTP 429, -32003, rate_limit_exceeded请求过多。data.window 说明哪个窗口已满。等待 Retry-After 秒(也在 data.retry_after 中),然后重试同一请求。
-32602未知的工具名。data.available_tools 列出该密钥可以调用的名称。使用 tools/list 中的名称。
isError: true, invalid_arguments参数未通过工具的 schema 校验。什么都没有执行。文本会指出每个错误的参数,如果参数名是猜的,还会给出实际存在的那个。修正参数。同样的参数会以同样的方式被拒绝。
isError: true, usage_limit_reached免费工作区已用完当月的邮件操作额度。等待 _meta 中的重置日期,或升级套餐。付费套餐没有月度上限。
isError: true, 其他工具已运行但失败:邮件不存在、服务商拒绝、收件人无效等。阅读 content[0].text。它会说明发生了什么,以及是否有邮件被发出。
HTTP
HTTP/1.1 403 Forbidden
WWW-Authenticate: Bearer error="insufficient_scope", ...

{
  "jsonrpc": "2.0",
  "id": 4,
  "error": {
    "code": -32004,
    "message": "Insufficient scope: the 'send:email' scope is required to call email_compose.",
    "data": { "error_code": "insufficient_scope", "required_scopes": ["send:email"], ... }
  }
}
HTTP
HTTP/1.1 429 Too Many Requests
Retry-After: 12

{
  "jsonrpc": "2.0",
  "id": 5,
  "error": {
    "code": -32003,
    "message": "Rate limit exceeded",
    "data": { "error_code": "rate_limit_exceeded", "window": "per_minute", "retry_after": 12, ... }
  }
}
JSON
{
  "jsonrpc": "2.0",
  "id": 6,
  "result": {
    "isError": true,
    "content": [{ "type": "text", "text": "Invalid arguments for email_read. The call was rejected before it ran, ..." }],
    "_meta": {
      "com.mcpemails/invalid_arguments": {
        "error_code": "invalid_arguments",
        "retryable": false,
        "errors": [{ "path": "arguments.since", "message": "..." }]
      }
    }
  }
}

分页

每个列表和搜索结果都以同样的四个字段结尾:

  • has_more:还有下一页时为 true。只有 has_more: false 才表示你已看完全部。
  • next_offset:把它作为 offset 传回,其他参数保持不变,即可获取下一页。has_more 为 false 时它为 null。
  • total:匹配数量,服务商无法统计时为 null。它永远不会与你手上的这一页矛盾。
  • total_is_estimate:当 total 是估计值或下限而非精确计数时为 true。

过长的邮件正文以同样方式分段:当 body_truncated 为 true 时,用 body_next_offset 作为 body_offset 再读一次。

重试与幂等键

发送后连接中断,你就无法知道邮件是否已发出。传入 idempotency_key 并用同一个键重试:操作只执行一次。

bash
curl -s https://mcpemails.com/api/mcp \
  -H "Authorization: Bearer $MCPEMAILS_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 7,
    "method": "tools/call",
    "params": {
      "name": "email_compose",
      "arguments": {
        "action": "send",
        "inbox": "you@example.com",
        "to": ["customer@example.com"],
        "subject": "Your order has shipped",
        "body": "Hi, your order is on its way.",
        "idempotency_key": "order-1042-shipped"
      }
    }
  }'
  • 适用于发送、回复、转发、定时发送、草稿写入,以及移动、标记、删除等邮箱更改。tools/list 会在每个接受它的工具的输入 schema 中显示 idempotency_key。
  • 最长 200 个字符。使用你自己系统里的内容,例如订单号加事件名。
  • 键与发送它的 API 密钥绑定,保留 24 小时。
  • 用同一个键和同样的参数重试不会再次执行。它返回 idempotent_replay: true、原始的 status,以及 result 中的原始结果,包括你可能丢失的 message_id。
  • 同一个键配不同的参数会以 idempotency_key_conflict 被拒绝。新操作请用新键。
  • 在第一次调用仍在运行时重试会返回 status: "processing"。稍后再试。
  • 如果邮件服务商在接受之前就拒绝了发送,则什么都没有发出,键会被释放,这样完全相同的重试会真正发送。
  • 当结果不确定时,重放会返回 status: "unknown"。在用新键再次发送之前,请先检查已发送文件夹。
JSON
{
  "idempotency_key": "order-1042-shipped",
  "idempotent_replay": true,
  "status": "succeeded",
  "result": { "message_id": "...", "inbox_id": "...", "status": "sent" },
  "message": "This logical request was already processed. ..."
}

发送审批

任何收件箱都可以暂留每一次发送,等人工审批。此时脚本的发送会返回带 status: "pending_approval" 的 approval_id 而不是直接发出,等有人在控制台批准后才会发送。这在所有套餐上都可用,是新自动化在证明自己之前的好默认设置。用同一个 idempotency_key 重试会报告该审批,而不是再创建一个。

速率限制

每个套餐对整个工作区都有一个每分钟上限。单个密钥可以用满套餐的每分钟限额;多个密钥则共享它。

套餐每分钟请求数Webhook
Free60否
Personal120否
Pro300是
Business1,000是
  • tools/call 的响应带有 RateLimit-Limit、RateLimit-Remaining 和 RateLimit-Reset(秒),对应最接近满额的那个窗口,客户端可以据此在触发限制前自行控制节奏。
  • 每个密钥还有小时和天窗口。429 会在 data.window 中指出哪个窗口已满。
  • 429 带有以秒计的 Retry-After。等待这么久,然后重试同一请求。
  • 免费套餐包含每月的邮件操作额度。付费套餐没有月度上限,也不按调用计费。

新邮件 webhook

在 Pro 和 Business 套餐上,当邮件到达收件箱时,MCPEmails 可以向你的 URL 发送 POST,让工作流由新邮件触发,而不必轮询。在控制台创建端点,选择它的收件箱,并复制只显示一次的签名密钥。URL 必须是 HTTPS,端口为 443 或 8443。用测试按钮发送一个带签名的 ping 事件。

事件

HTTP
POST /your/webhook HTTP/1.1
Content-Type: application/json
MCPEmails-Event-Id: evt_...
MCPEmails-Event-Type: message.received
MCPEmails-Signature: t=1792843200,v1=5f2b...

{
  "id": "evt_...",
  "type": "message.received",
  "created_at": "2026-10-24T09:20:00.000Z",
  "workspace_id": "...",
  "inbox_id": "...",
  "folder": "INBOX",
  "count": 1,
  "message_ids": ["..."]
}
  • type 为 message.received。message_ids 列出该收件箱 INBOX 文件夹中的新邮件,每个事件最多 10 条;count 是到达的数量,可能更多。
  • 默认情况下负载只包含 id,不含内容。设置为包含邮件头的端点还会收到一个 messages 列表,含每封邮件的 id、from 和 subject。
  • 用 API 密钥通过 email_read(action: "read"、inbox_id 和 message_id)获取邮件。该密钥的权限范围和收件箱访问照常生效。
  • 投递通常在邮件到达后约两分钟内完成。收件箱按计划检查,所以不是即时的。

验证签名

每次投递都带有 MCPEmails-Signature: t=<unix 秒>,v1=<hex>,其中 v1 是以端点密钥计算的 HMAC-SHA256,输入为时间戳、一个点和原始请求体。密钥是显示的完整 secret,包括 whsec_ 前缀。对原始请求体重新计算签名,用恒定时间比较,并拒绝超过五分钟的时间戳。

JavaScript
import crypto from 'node:crypto';

// rawBody: the request body exactly as received, before JSON.parse.
export function verifyMcpemailsSignature(rawBody, header, secret, toleranceSeconds = 300) {
  const parts = Object.fromEntries(
    String(header ?? '').split(',').map((part) => part.trim().split('=')),
  );
  const timestamp = Number(parts.t);
  if (!Number.isFinite(timestamp)) return false;
  if (Math.abs(Date.now() / 1000 - timestamp) > toleranceSeconds) return false;

  const expected = crypto
    .createHmac('sha256', secret)
    .update(`${parts.t}.${rawBody}`)
    .digest();
  const received = Buffer.from(parts.v1 ?? '', 'hex');
  return received.length === expected.length && crypto.timingSafeEqual(received, expected);
}

重试

  • 在 10 秒内以任意 2xx 状态响应。其他一切都算失败,包括重定向,我们不会跟随重定向。
  • 失败的投递会在 1 分钟、5 分钟、30 分钟、2 小时、6 小时和 24 小时后重试。每次重试都用新的时间戳重新签名。
  • 连续失败 24 小时或连续失败 50 次的端点会被停用,并通过邮件通知工作区所有者。你可以在控制台重新启用它。
  • 用 MCPEmails-Event-Id 忽略已经处理过的投递。重试会带同一个事件 id。

实用示例

n8n:由新邮件触发工作流

  • 添加一个 HTTP 方法为 POST 的 Webhook 触发节点,并把它的生产 URL 注册为 MCPEmails 控制台中的 webhook 端点。
  • 添加一个 HTTP Request 节点:方法 POST,URL https://mcpemails.com/api/mcp,身份验证选 Generic Credential Type → Header Auth,名称为 Authorization,值为 Bearer mcpe_...。
  • 开启 Send Body,选择 JSON,用下面的请求体读取新邮件。后续节点可以在 result.structuredContent 中拿到邮件。
  • 要在 n8n 中校验签名,请在 Webhook 节点上启用 Raw Body,并在 Code 节点中运行上面的验证代码。自托管的 n8n 需要用 NODE_FUNCTION_ALLOW_BUILTIN=crypto 放行 crypto 模块。
JSON
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "email_read",
    "arguments": {
      "action": "read",
      "inbox_id": "{{ $json.body.inbox_id }}",
      "message_id": "{{ $json.body.message_ids[0] }}"
    }
  }
}

若要让 AI Agent 节点自己读取和发送邮件,请参阅 n8n 指南。

Claude Code

通过请求头中的密钥添加服务器。这适合没有浏览器完成 OAuth 登录的无头机器和 CI:

bash
claude mcp add --transport http mcpemails https://mcpemails.com/api/mcp \
  --header "Authorization: Bearer $MCPEMAILS_KEY"

Claude Code 指南 介绍了 OAuth 登录和权限范围的选择。

一段简短的 Node 脚本

逐页列出一个收件箱中的所有未读邮件,并在遇到 429 时等待:

JavaScript
// node agent.mjs  (Node 18 or later, MCPEMAILS_KEY in the environment)
const ENDPOINT = 'https://mcpemails.com/api/mcp';
let nextId = 1;

async function callTool(name, args) {
  const res = await fetch(ENDPOINT, {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${process.env.MCPEMAILS_KEY}`,
      'Content-Type': 'application/json',
      Accept: 'application/json',
    },
    body: JSON.stringify({ jsonrpc: '2.0', id: nextId++, method: 'tools/call', params: { name, arguments: args } }),
  });
  if (res.status === 429) {
    const wait = Number(res.headers.get('Retry-After') ?? 1);
    await new Promise((resolve) => setTimeout(resolve, wait * 1000));
    return callTool(name, args);
  }
  const reply = await res.json();
  if (reply.error) throw new Error(`${reply.error.code}: ${reply.error.message}`);
  if (reply.result.isError) throw new Error(reply.result.content[0].text);
  return reply.result.structuredContent;
}

const inbox = 'you@example.com';
let offset = 0;
do {
  const page = await callTool('email_read', { action: 'list', inbox, unread: true, limit: 50, offset });
  for (const m of page.messages) console.log(m.id, m.from?.email, m.subject);
  offset = page.has_more ? page.next_offset : null;
} while (offset !== null);

OpenClaw

OpenClaw 默认使用 OAuth 登录;OpenClaw 指南 有完整步骤。若要改用限定权限的密钥,请把它放进服务器条目的 headers 映射中,并且不要设置 auth,因为 OpenClaw 会忽略设为 OAuth 的条目上的静态 Authorization 头。

JSON
{
  "mcp": {
    "servers": {
      "mcpemails": {
        "url": "https://mcpemails.com/api/mcp",
        "transport": "streamable-http",
        "headers": { "Authorization": "Bearer mcpe_YOUR_KEY_HERE" }
      }
    }
  }
}

从一个收件箱免费开始

创建一个密钥,调用 tools/list,看看你自己的邮件以 JSON 形式返回。