mcpField
E
Email Agent Mcp

Email Agent Mcp

本地服务
github.comAI 与智能体72 天前更新

关于 Email Agent Mcp

email-agent-mcp 是连接 AI Agent 与 Microsoft 365 / Outlook、Gmail 邮箱的开源 TypeScript MCP 服务。它提供邮件阅读、搜索、起草和邮箱操作,并通过允许列表及保守默认设置约束发送和删除。

主要功能

  1. 01阅读与搜索邮件
  2. 02查看会话线程
  3. 03创建和更新草稿
  4. 04通过允许列表发送与回复
  5. 05整理邮件和文件夹
  6. 06只读权限配置

适用场景

  1. 01在收件箱中搜索邮件
  2. 02起草邮件或回复邮件
  3. 03将 Agent 发信限制为获准收件人
  4. 04配置只读邮箱访问

MCP 相关

通过 stdio 向 MCP 客户端提供邮件和邮箱管理工具。支持 Microsoft 365 / Outlook 与 Gmail,具体工具取决于服务提供商和权限配置。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

mcp.json · 通用配置
{
"mcpServers": {
"email-agent": {
"command": "npx",
"args": [
"-y",
"email-agent-mcp"
]
}
}
}
启动命令npx -y email-agent-mcp

本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
npmemail-agent-mcp0.4.0

工具

26

收录的工具列表 · 更新于 3 周前

参数类型必填说明
mailboxstring否
unreadboolean否
limitnumber否
offsetnumber否
folderstring否

详细介绍

Agent Email

npm version npm downloads License: Apache-2.0 CI codecov GitHub stargazers Tests: Vitest OpenSpec Traceability Socket Badge install size

English | Español | 简体中文 | Português (Brasil) | Deutsch

UseJunior 推出的 email-agent-mcp —— 为 AI Agent 提供本地邮件连接能力。

Agent Email 是一个开源 TypeScript MCP 服务,可让 Claude Code、Cursor、Gemini CLI、OpenClaw 及其他兼容 MCP 的运行时通过你自己的邮箱读取邮件、搜索邮件会话、起草回复、为邮件添加标签、更改已读状态、移动邮件并发送邮件。目前支持 Microsoft 365 / Outlook 和 Gmail。默认采用安全优先策略:除非你明确配置允许名单,否则 Agent 无法发送邮件。

快速开始

npx -y email-agent-mcp

交互式设置向导会引导你完成 OAuth 配置和邮箱选择。

当前可用功能

  • 通过 MCP stdio 访问 Microsoft 365 / Outlook 邮箱
  • list_emails、read_email、search_emails 和 get_thread
  • create_draft、update_draft、send_draft、send_email 和 reply_to_email
  • label_email、mark_read 和 move_to_folder
  • 发送允许名单、默认禁用删除,以及经过清理的错误信息

当前发布准备阶段已通过真实 Outlook 邮箱验证读取、草稿、发送、分类、移动和已读状态等流程。

为什么要开发它

AI Agent 需要读取、回复和处理邮件,但邮件 API 十分复杂。OAuth 流程、Graph delta 查询、Gmail 推送订阅、HTML 转 Markdown、邮件会话语义——每个服务提供商都有各自的细节。

Agent Email 将这些复杂性封装为确定性的 MCP 工具,并配备安全防护:

  • 发送和接收允许名单,用于控制 Agent 可以联系的对象
  • 默认禁用删除(需要明确选择启用)
  • 错误信息清理,可移除 API 密钥、文件路径和堆栈跟踪
  • 正文文件沙箱,防止路径遍历

在 Claude Code 中使用

添加到 ~/.claude/settings.json 或项目的 .claude/settings.json:

{
  "mcpServers": {
    "email-agent-mcp": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "email-agent-mcp"]
    }
  }
}

在 Cursor 中使用

// .cursor/mcp.json
{
  "mcpServers": {
    "email-agent-mcp": {
      "command": "npx",
      "args": ["-y", "email-agent-mcp"]
    }
  }
}

在 Gemini CLI 中使用

gemini extensions install https://github.com/UseJunior/email-agent-mcp

在 OpenClaw 中使用

在 ~/.openclaw/openclaw.json 中添加 mcp 块:

{
  // ... existing config ...
  mcp: {
    servers: {
      email: {
        command: "npx",
        args: ["tsx", "/path/to/email-agent-mcp/packages/email-mcp/src/serve-entry.ts"],
        transport: "stdio"
      }
    }
  }
}

版本说明:mcp 配置键要求 OpenClaw app >= 2026.3.24。如果 CLI 版本低于 app,验证时可能会拒绝此键,即使网关接受它也是如此。请在 NemoClaw 目录中运行 npm install openclaw@latest 更新 CLI,或直接使用 launchctl kickstart -k gui/501/ai.openclaw.gateway 重启网关。

邮件监视器

监视器会轮询你的邮箱,并在收到新邮件时向 OpenClaw 发送唤醒信号:

# Set the hooks token (must match hooks.token in openclaw.json)
export OPENCLAW_HOOKS_TOKEN="your-hooks-token"

# Start the watcher (defaults to http://localhost:18789/hooks/wake)
npm run dev:watch

监视器至少需要配置一个邮箱。请先运行 npx email-agent-mcp 或 npm run dev:configure,完成 OAuth 流程。

发布准备冒烟测试

录制演示前,请针对真实邮箱和安全的发送允许列表运行实时冒烟测试脚本。该脚本会测试:

  • get_mailbox_status
  • list_emails + read_email
  • mark_read 未读 -> 已读 -> 未读
  • 对安全的收件箱候选邮件执行 label_email
  • create_draft
  • 仅创建草稿的 reply_to_email
  • 可选的 send_email

示例:

EMAIL_AGENT_MCP_HOME=/tmp/email-agent-mcp-live \
AGENT_EMAIL_SEND_ALLOWLIST=/tmp/email-agent-mcp-live/send-allowlist.json \
npm run launch:prep:smoke -- --live-write --send-to [email protected]

默认的安全候选邮件选择逻辑会在收件箱中查找来自 [email protected] 的邮件,这样你就可以使用公开安全的邮件演练录制流程,而不是使用客户邮件。 如果邮箱状态中的名称不是电子邮件地址,请传入 --reply-sender <email> 或设置 EMAIL_AGENT_MCP_REPLY_SENDER,以便脚本找到自己发送的邮件来检查草稿回复。

工具参考

权限范围配置

在配置并启动服务前设置 EMAIL_AGENT_MCP_SCOPE_PROFILE,以选择向 Agent 暴露的权限。为保持向后兼容,默认值为 full。

配置文件Microsoft 委派权限范围暴露的工具
observeMail.Read、User.Read、offline_access只读邮件工具,不包括 list_inbox_rules(见下文)
full(默认)Mail.Read、Mail.ReadWrite、Mail.Send、MailboxSettings.ReadWrite、User.Read、offline_access所有工具

对于仅用于观察的部署,请在配置和运行时都设置该配置文件,以确保 OAuth 授权同意与 MCP 工具列表一致:

export EMAIL_AGENT_MCP_SCOPE_PROFILE=observe
npx email-agent-mcp configure
npx email-agent-mcp serve

observe 的权限范围是 full 权限范围的严格子集。这使该配置文件易于采用:已经同意完整权限范围的租户会静默授予 observe,因此从 full 切换到 observe 无需重新授权。同理,从 observe 切换到 full 则需要新的交互式授权,因为它请求了此前未授予的权限范围。

出于同样的原因,observe 不会暴露 list_inbox_rules。Graph 将 /mailFolders/inbox/messageRules 置于 MailboxSettings 权限之后,而 Entra 将 MailboxSettings.Read 视为与 full 的 MailboxSettings.ReadWrite 不同的权限范围,而非后者隐含包含的权限。请求该权限会破坏子集特性,并迫使每个 observe 部署都重新授权;在限制用户授权的租户中,还会触发管理员审批请求。如果需要查看收件箱规则,请使用 full。

无效的配置文件值会导致启动停止,而不会静默授予更广泛的访问权限。如果缓存的凭据未涵盖该配置文件所需的权限范围,服务会立即失败并给出可执行的错误提示,而不会阻塞在交互式登录流程中。

observe 能保证和不能保证的内容

observe 始终会从 MCP 工具集中移除写入工具,因此 Agent 无法调用这些工具。此项保证适用于所有环境。

只有当邮箱此前尚未同意写入权限范围时,observe 才会缩小其 OAuth 令牌 的权限。Entra 会签发携带用户或租户此前已为该应用同意的所有权限范围的访问令牌,而不只是获取令牌时请求的子集。因此,如果你将 observe 用于此前配置为 full 的邮箱,底层令牌仍会携带 Mail.ReadWrite 和 Mail.Send;只有工具集会缩减。

若要获得真正遵循最小权限原则的令牌,请使用从未获授写入权限范围的邮箱同意 observe——针对委派权限仅包含 Mail.Read/User.Read 的应用注册执行全新的 configure。除非你能控制授权,否则应将工具集缩减视为纵深防御,而非 OAuth 边界。

工具

full 配置文件会暴露 27 个 MCP 工具;observe 会省略所有操作标记为会修改邮箱的工具:

工具描述类型
list_emails列出近期邮件并进行筛选读取
read_email以 Markdown 格式读取完整邮件内容,或使用 format: "html" 读取原始 HTML读取
search_emails在各邮箱中进行全文搜索读取
list_mailboxes列出已配置的邮箱及其状态和默认邮箱读取
get_mailbox_status查看连接状态和警告读取
get_thread获取完整的对话上下文读取
list_attachments列出邮件的附件元数据读取
download_attachment将文件附件下载为 base64,或使用 save_to 将其保存到沙盒目录读取
download_message将整封邮件保存为原始 .eml 文件到沙盒目录读取
send_email发送新邮件(受允许列表限制)写入
reply_to_email在邮件会话中回复(发送时受允许列表限制)写入
create_draft创建邮件草稿写入
update_draft更新草稿内容写入
send_draft发送已保存的草稿写入
list_scheduled_sends列出由服务提供商暂存的待发送定时邮件(Microsoft 365)读取
cancel_scheduled_send取消待发送的定时邮件(Microsoft 365)破坏性操作
label_email应用标签/类别写入
flag_email标记/取消标记邮件写入
mark_read标记为已读/未读写入
move_to_folder在文件夹之间移动写入
delete_email删除(需要操作员环境变量和调用方标志)破坏性操作
list_folders递归列出文件夹及计算出的路径(Microsoft 365)读取
create_folder创建自定义子文件夹(Microsoft 365)写入
delete_folder删除自定义文件夹(需要操作员环境变量和调用方标志);系统文件夹受保护(Microsoft 365)破坏性操作
list_inbox_rules列出服务器端收件箱规则(Microsoft 365)读取
create_inbox_rule创建持久的安全收件箱规则;禁止转发、重定向、删除以及移至“已删除邮件”(Microsoft 365)写入
delete_inbox_rule删除服务器端收件箱规则(需要操作员环境变量和调用方标志)(Microsoft 365)破坏性操作

这是一个跨服务提供商共享的工具集。虽然提供了 label_email、 flag_email、mark_read 和 move_to_folder,但 Gmail 适配器有意不实现这些更改操作。它们会在发出任何 Gmail 更改请求之前以 NOT_SUPPORTED 失败。默认的 gmail.readonly 加 gmail.compose 授权也不允许这些更改操作;不要添加 gmail.modify 来尝试启用这些工具。只有适配器和授权均支持这些操作的服务提供商才能使用这些工具。

在 Gmail 上,delete_email 仅通过 users.drafts.delete 删除草稿, 该操作由 gmail.compose 授权。传入草稿 ID(r…)或草稿邮件的 ID(即 list_emails 使用 folder: "drafts" 时返回的 ID)均可。删除是永久性的,因为 Gmail 没有草稿回收站;但此操作仍受相同的 AGENT_EMAIL_DELETE_ENABLED 门控以及 user_explicitly_requested_deletion 标志保护;不需要 AGENT_EMAIL_HARD_DELETE_ENABLED。删除已发送或已接收的 Gmail 邮件会返回 NOT_SUPPORTED,因为这需要 gmail.modify。在 Gmail 上,update_draft 同样接受任一 ID。每次更新草稿时,Gmail 都会为其分配新的邮件 ID,而草稿 ID 保持不变,因此编辑后建议使用草稿 ID(或重新列出草稿)。 list_emails、search_emails 和 get_thread 返回的每一行,以及 read_email 的响应,始终都包含一个 isDraft 布尔值。isDraft: true 表示该邮件是尚未发送的草稿:它尚未发送,而且其 receivedAt 是提供方提供的元数据,并非邮件已送达的证据。此字段绝不会省略,因此使用方 Agent 可以区分“不是草稿”和“未报告草稿状态”——但请注意,false 仅表示提供方未将该邮件标记为尚未发送的草稿,并不表示邮箱所有者发送了该邮件(收到的邮件也会是 false)。草稿仍和以前一样出现在列表和搜索结果中。

文件夹和收件箱规则管理需要 Microsoft Graph MailboxSettings.ReadWrite 授权。升级后,现有的 Microsoft 邮箱连接必须重新授权。Gmail 使用标签,而非层级文件夹或服务器端 Exchange 规则,因此这六个工具对 Gmail 邮箱会返回 NOT_SUPPORTED。

正文格式

默认情况下,正文在双向传输时都使用 Markdown。这是有意为之——Markdown 的 Token 效率高,日常读取的成本应保持低廉。两个方向都可以选择不使用 Markdown。

写入——send_email、reply_to_email、create_draft 和 update_draft 接受可选的 format:

format行为
markdown(默认)通过 marked 转换为 HTML(GFM,breaks: true)。Markdown 中嵌入的原始 HTML 会保留。
html原样传递——按原样发送你的 HTML。
text不进行转换;以纯文本发送。

html 会未经清理地原样传递:没有清理器、允许列表,也不会重写你的标记。内联 CSS 和任意标签都会原样传输——这使邮件可以使用样式,也意味着发送内容由你负责。唯一的默认修改是下方的强制黑色包装层;设置 force_black: false 后,正文会逐字节原样传递。

对于 markdown 和 html,转换后的 HTML 会包在 <div style="color: #000000;"> 中,以避免 Outlook 深色模式将文字变成白底白字。

正文文件——send_email、create_draft 和 update_draft 也接受 body_file:一个 .md、.html 或 .txt 文件的路径(相对于 EMAIL_MCP_SAFE_DIR 读取,默认是进程工作目录,并包括任何 AGENT_EMAIL_ALLOWED_DIRS 根目录),用于替代 body 作为正文。.md 正文文件可以以 YAML frontmatter 块开头:

对于 update_draft,只有非回复草稿允许使用 body 和 body_file,且必须设置 replace_body: true;届时存储的正文将被整体替换。回复草稿正文包含由提供方组装的引用历史,无法安全编辑,因此请改为创建新草稿。回复草稿仍可更新主题、收件人和附件。

---
to: [email protected]
subject: Quarterly summary
format: html
force_black: false
---
<p>The body starts after the closing delimiter.</p>

可识别的键包括 to、cc、bcc、subject、reply_to、draft、format 和 force_black(draft: true 会将 send_email 调用转为保存草稿)。bcc 适用于 create_draft 和 update_draft;如果正文文件设置了 bcc,send_email 会拒绝该文件,而不是在不发送密件抄送的情况下发送邮件。frontmatter 中的值会覆盖同名工具参数。frontmatter 仅从 .md 文件解析,文件扩展名不会决定格式——如果没有明确指定 format 工具参数,即使是 .html 正文文件也会默认按 Markdown 转换;若要原样传递,请传入 format: "html"。

读取——read_email 接受可选的 format,值为 markdown(默认)或 html:

{ "id": "AAMkAD...", "format": "html" }

format: "html" 会逐字返回邮件的原始正文 HTML。当你需要 Markdown 无法保留的样式(如 color、background-color、text-decoration、<u>)时,可以使用此格式;例如,只修改格式化正文中的一句话,同时保留其余内容。经过 Markdown 路径时,这些样式会在输出过程中被静默移除。

响应还会附带两个字段:

  • bodyFormat — 始终存在:markdown、html 或 text。如果你请求的是 html,但邮件没有 HTML 部分,则会得到 text,此时返回纯文本正文。写回正文前请先检查此字段。
  • bodyTruncated — 仅当正文超出 format: "html" 的 256 KB 响应预算时才会出现且值为 true(与之前一样,markdown 路径不受大小限制)。请勿将截断的正文写回草稿。

原始 HTML 消耗的令牌远多于其 markdown 精简版,因此除非需要保留样式,否则请保持默认设置不变。strip_quoted_history 和 strip_signatures 是针对 markdown 格式文本的转换,在 format 为 html 时不会应用——原始 HTML 会原样返回。

**写回邮件。**传入 format: "html" 和 force_black: false:

{ "draft_id": "AAMkAD...", "body": "<edited html>", "format": "html", "force_black": false }

force_black 默认为 true,会将你发送的任何 HTML 包裹在 <div style="color: #000000;"> 中。这适用于你自行编写的 HTML,但对于刚读取后要写回的正文,每次循环都会再嵌套一层——经过 15 次修改后,就会有 15 层嵌套的 div。设置 force_black: false 后,内容在往返过程中会保持原样。

定时发送

send_email 和 send_draft 接受 scheduled_send_at,即带明确时区的 ISO 8601 未来时间戳。Microsoft 365 会在服务端保留邮件,因此即使此进程退出,邮件仍会发送。邮件处于待发送状态时,可使用返回的 messageId 调用 cancel_scheduled_send 取消;也可通过 list_scheduled_sends 检查待处理邮件。该列表涵盖你在 Outlook 中安排的邮件,而不仅限于通过此服务安排的邮件——Outlook 会将暂存的邮件放在任意位置(通常是“已删除邮件”),因此查找时会扫描邮箱而非某个文件夹,并且只报告发送时间尚未到来的邮件。

当暂存的草稿移至“已发送邮件”时,Microsoft Graph 会更改邮件 ID,因此返回的 ID 是用于发送前管理的句柄,并非永久的已发送邮件 ID。Gmail 的公开 API 不提供定时发送功能;对于 Gmail,所有定时发送接口都会返回 NOT_SUPPORTED,即时发送则不受影响。

出站附件

send_email、reply_to_email、create_draft 和 update_draft 都接受可选的 attachments 数组。每个条目可指定沙箱文件 path(相对于 EMAIL_MCP_SAFE_DIR 读取,默认值为进程工作目录;也可使用 AGENT_EMAIL_ALLOWED_DIRS 根目录,见下文)或内联 base64,以及可选的 filename / mimeType 覆盖值:

{
  "to": "[email protected]",
  "subject": "Signed agreement",
  "body": "Attached as requested.",
  "attachments": [
    { "path": "./out/agreement.pdf" },
    { "base64": "iVBORw0KGgo...", "filename": "screenshot.png" }
  ]
}

每个文件的大小上限为 25MB。如果文件不适用于较小的内联请求路径,Microsoft Graph 会自动使用分块上传会话;如果邮件超过 5MB,Gmail 会自动使用原始 MIME 媒体上传。这两种方式都适用于发送、回复以及创建/更新草稿。对于 update_draft,省略 attachments 会保留草稿中现有的文件;传入数组(即使为空)则会替换这些文件。

附加工作目录之外的文件 — 将 AGENT_EMAIL_ALLOWED_DIRS 设置为由分隔符分开的绝对目录列表(macOS/Linux 使用 :,Windows 使用 ;;开头的 ~ 会展开),供 attachments[].path 和 body_file 读取:

{
  "mcpServers": {
    "email-agent-mcp": {
      "command": "npx",
      "args": ["-y", "@usejunior/email-agent-mcp"],
      "env": { "AGENT_EMAIL_ALLOWED_DIRS": "~/Downloads:/Volumes/Shared/Contracts" }
    }
  }
}

调用方路径的解析方式 — 以下两种情况都会返回 FILE_NOT_FOUND,因此容易被误认为是文件缺失:

传入的路径解析位置能否在允许的根目录中找到文件?
contract.pdfEMAIL_MCP_SAFE_DIR(默认值:cwd)❌ 相对路径不会搜索额外的根目录
~/Downloads/contract.pdfEMAIL_MCP_SAFE_DIR — 不会展开 ~❌
/Users/you/Downloads/contract.pdf依次检查每个根目录✅

~ 简写会在 AGENT_EMAIL_ALLOWED_DIRS(运维人员的配置)中展开,但不会在 attachments[].path 或 body_file(调用方的参数)中展开 — 请将这些参数指定为绝对路径。相对路径会被刻意限制在安全目录内:如果搜索每个允许的根目录来查找不带路径的 contract.pdf,就可能悄悄附加最先找到的副本。

每个根目录都会在进行包含关系检查前通过 realpath 规范化:如果允许列表中的根目录本身是符号链接,则会解析到其真实位置;无法规范化的根目录不会授予任何访问权限;逃逸出所有根目录的符号链接仍会被拒绝。未设置该变量时(默认情况),工作目录是唯一的根目录 — 因此,如果 Agent 无法访问某个文件,应请你将其所在目录加入允许列表,而不是把机密文档复制到 git 工作树中。

将某个目录加入允许列表,意味着信任所有能够写入该目录的用户。路径验证和打开是分开的操作,因此,如果某个主体能在这两步之间替换允许根目录 内的 目录,仍可重定向读取操作;只应将其祖先目录不可被不受信任用户写入的目录加入允许列表。最终打开文件时会使用 O_NOFOLLOW,因此文件本身无法在验证后被替换为符号链接。

将附件和邮件保存到磁盘

download_attachment 默认以内嵌 base64 格式返回(默认上限为 5 MB,最高为 25 MB)。传入 save_to 后,服务会改为写入文件。返回结果仅包含元数据,因此大型附件(屏幕录制、音频、大型 PDF)不会经过 Agent 的上下文:

{ "message_id": "…", "attachment_id": "…", "save_to": "/Users/you/Downloads/records" }
{ "success": true, "path": "/Users/you/Downloads/records/Signed_Agreement.pdf",
  "filename": "Signed_Agreement.pdf", "original_filename": "Signed Agreement.pdf",
  "mimeType": "application/pdf", "size": 782957, "sha256": "…" }

download_message 会将收到的邮件原样写入 <subject>.eml,格式为原始 RFC 822 MIME(Graph /$value、Gmail format=raw),并返回相同的元数据。可用它在附件旁保存一份邮件记录。

save_to 指定一个目录,路径解析方式与 body_file 和 attachments[].path 完全相同。相对路径相对于 EMAIL_MCP_SAFE_DIR 解析,而 AGENT_EMAIL_ALLOWED_DIRS 中的根目录必须使用绝对路径。..、以 ~ 开头的路径,以及指向沙盒外部的符号链接都会被拒绝。不存在的子目录会自动创建。已有文件绝不会被覆盖:如果文件名冲突,会添加数字后缀(report.pdf、report-1.pdf、…)。文件的创建权限为 0600。size 和 sha256 描述实际写入的字节,这可能与 list_attachments 报告的大小略有差异,因为服务提供商会计算 MIME 开销。使用 save_to 时,max_size_mb 的默认上限和最大上限均为 150 MB。内嵌下载超出上限时会失败,并返回 ATTACHMENT_TOO_LARGE,提示改用 save_to。

服务提供商支持

服务提供商状态软件包
Microsoft 365(Graph API)完全支持@usejunior/provider-microsoft
Gmail支持通过交互式命令行 OAuth(默认客户端或自有客户端)或手动设置刷新令牌@usejunior/provider-gmail

使用 email-agent-mcp configure --provider gmail 运行本地浏览器 OAuth 流程,或在 ~/.email-agent-mcp/tokens/ 下添加手动配置的邮箱令牌文件。请参阅下文的 Gmail 设置 和 packages/provider-gmail/README.md。

Gmail 设置

Gmail 支持两种 OAuth 路径。两种方式最终结果相同:在你的计算机上获取刷新令牌,Gmail API 调用直接从你的计算机发往 Google。

路径命令是否需要 Google Cloud 项目?
默认 OAuth 客户端email-agent-mcp configure --provider gmail否
使用自有密钥(BYOK)同一命令加上 --client-id / --client-secret是,需要你自己的项目

目前建议使用 BYOK。 默认 OAuth 客户端在验证期间仍处于 Google 的“Testing”发布状态,因此最多只能注册 100 名测试用户,并且在授权同意时会显示“Google 尚未验证此应用”的提示页面。Gmail 受限范围的验证需要进行 CASA 安全评估,耗时数周;进度可在 issue #112 中查看。BYOK 可避开共享的 100 用户上限,并让你自行控制应用的发布状态;在你发布自己的应用之前,它仍受 Google Testing 状态的限制。

选择 BYOK 的其他原因包括:专属 API 配额、由你自行管理隐私政策和验证状态,以及无需依赖托管代理 https://oauth.usejunior.com。

请求的范围

Agent Email 默认恰好请求以下两个 Gmail 范围:

https://www.googleapis.com/auth/gmail.readonly
https://www.googleapis.com/auth/gmail.compose

gmail.readonly 是读取邮件和会话所必需的; gmail.compose 用于管理草稿和发送邮件,但不授权 users.threads.get 或 users.messages.get。默认授权不包含 gmail.modify。此外,Gmail 适配器有意不支持标签更改、已读状态更改、移动、移至垃圾箱,以及删除已发送或已接收的邮件,因此这些工具会安全失败并返回 NOT_SUPPORTED。在默认授权下可以删除草稿。请将两个范围都添加到 OAuth 授权同意屏幕。

明确设置了 GMAIL_OAUTH_SCOPES 的部署必须将其更新为上述两个以空格分隔的范围。新的授权和重复授权都必须重新同意这对新范围。现有邮箱文件及其存储的刷新令牌元数据保持不变。

BYOK:创建自己的 Google OAuth 客户端
  1. 创建项目:前往 Google Cloud Console, 或选择现有项目。
  2. 启用 Gmail API:前往 APIs & Services → Library → Gmail API → Enable。
  3. 配置 OAuth 授权同意屏幕:前往 APIs & Services → OAuth consent screen:
    • 如果使用个人 @gmail.com 账号,用户类型选择 External;如果使用 Google Workspace,且只有你自己的组织需要访问权限,则选择 Internal。
    • 添加 https://www.googleapis.com/auth/gmail.readonly 和 https://www.googleapis.com/auth/gmail.compose。
    • 应用处于 Testing 状态期间,请在 Test users 下添加你自己的 Gmail 地址, 否则授权会被拒绝。
  4. 创建 OAuth 客户端:前往 APIs & Services → Credentials → Create credentials → OAuth client ID。选择应用类型 Desktop app。 必须使用 Desktop:configure 会在临时回环端口上启动一次性监听器 (http://127.0.0.1:<port>/oauth2callback),而只有 Desktop 客户端允许 Google 接受任意回环端口,无需预先注册确切的重定向 URI。Web application 客户端会因 redirect_uri_mismatch 而失败。
  5. 复制客户端 ID 和客户端密钥。
BYOK:将凭据提供给 email-agent-mcp

通过标志传入两部分凭据:

npx email-agent-mcp configure \
  --provider gmail \
  --mailbox personal \
  --client-id YOUR_GOOGLE_CLIENT_ID \
  --client-secret YOUR_GOOGLE_CLIENT_SECRET

或者设置这两个命名空间环境变量,并省略标志:

export AGENT_EMAIL_GMAIL_CLIENT_ID=YOUR_GOOGLE_CLIENT_ID
export AGENT_EMAIL_GMAIL_CLIENT_SECRET=YOUR_GOOGLE_CLIENT_SECRET

npx email-agent-mcp configure --provider gmail --mailbox personal

两部分凭据都必需。只提供其中一项会报错退出,而不会静默回退到默认客户端。两项都不提供时,则选择默认 OAuth 客户端。

浏览器会打开 Google 的授权同意屏幕,CLI 会在回环地址上接收回调,使用 PKCE 交换授权码,并将邮箱信息写入 ~/.email-agent-mcp/tokens/<safe-key>.json,其中包含 "source": "byok",以及你的 clientId、clientSecret 和生成的 refreshToken。此后令牌刷新会直接发送到 Google 的令牌端点;不会经过任何中介。

对已保存的邮箱重新运行 configure 时,会复用已保存的凭据,因此只需传入一次标志。对于之前使用默认客户端配置的邮箱,传入 --client-id 和 --client-secret 可将其迁移到 BYOK。

BYOK:避免授权在 7 天后过期

当你自己的 OAuth 应用处于 Testing 发布状态时,Google 会在 7 天后使刷新令牌过期,因此大约每周会提示重新授权一次。email-agent-mcp status 会在邮箱接近此期限时发出警告。发布应用(OAuth consent screen → Publish app)即可取消 7 天的过期限制。由于应用由你所有,且你是唯一用户,100 名测试用户的上限对你也不会产生影响。

断开 Gmail 并撤销访问权限

断开连接分为两个独立步骤:

  1. 停止所有正在运行的 email-agent-mcp 进程。在 Finder 中打开 ~/.email-agent-mcp/tokens/,找到你要断开连接的邮箱对应的唯一 JSON 文件, 并将该文件移到废纸篓。不要打开、粘贴或分享文件内容;如果配置了其他邮箱, 不要删除整个 ~/.email-agent-mcp 目录。如果设置了 EMAIL_AGENT_MCP_HOME, 请改用该目录下的 tokens/ 文件夹。
  2. 打开 Google 账号第三方 连接,选择 Email Agent MCP(或你的 BYOK 应用名称),然后移除其访问权限。

删除本地文件后,此安装将无法使用已保存的凭据。移除 Google 账号连接则会撤销 Google 端的授权。之后运行 email-agent-mcp status,确认该邮箱已不再配置。

安全默认设置

Agent Email 采用严格的默认设置,你可以按需放宽:

  • 发送允许列表:默认为空——添加收件人之前,Agent 无法发送邮件
  • 接收允许列表:默认接受所有发件人——用于控制哪些发件人会触发监视器
  • 默认禁用删除:Agent 默认无法删除邮件。必须同时满足以下两个条件:
    1. 操作者在 email-agent-mcp 进程环境中设置 AGENT_EMAIL_DELETE_ENABLED=true(永久删除还需设置 AGENT_EMAIL_HARD_DELETE_ENABLED=true)。更改后必须重启。Gmail 只能删除草稿,且删除草稿始终是永久删除;此操作只需设置 AGENT_EMAIL_DELETE_ENABLED。
    2. 调用方在工具调用中传入 user_explicitly_requested_deletion: true。
  • 错误信息清理:从错误响应中删去 API 密钥、文件路径和堆栈跟踪
  • 邮件正文文件沙箱:禁止 ../ 路径遍历和符号链接,并检测二进制文件
  • 重复投递防护:默认启用——15 分钟内重复发送相同的邮件、回复或发送草稿时,将拒绝操作,以免重复投递
重复投递防护

提供方的发送端点(Graph POST /sendMail、Gmail users.messages.send)不接受幂等键,因此 Agent Email 对每次投递只发送一次,绝不会自动重试。这样可以防止库重复发送邮件,但无法防止调用方:如果 Agent 丢失了工具结果——例如上下文被压缩、传输中断、监管器重启了当前轮次,或有人重试了看起来卡住的操作——就会重放同一条已批准的指令,而第二次调用看起来与第一次完全相同。

因此,send_email、reply_to_email 和 send_draft 会在进程内账本中记录每次发送,并按有效操作输入的摘要进行索引——包括邮箱、收件人、主题、渲染后的正文、附件内容,以及回复的父邮件或草稿 ID。(这里记录的是有效输入,而非最终传输字节:提供方可能会在发送时转换邮件,例如 Graph 会将主题截断为 255 个字符,因此两个不同的输入最终可能发送出相同的邮件。防护机制捕获的是重放的工具调用,而这才是真正会发生的情况。)在时间窗口内重复调用时,会在发送前拒绝:

代码含义处理方式
DUPLICATE_SEND_IN_FLIGHT一封完全相同的邮件尚未完成发送等待首次调用完成
DUPLICATE_SEND_BLOCKED一封完全相同的邮件已成功发送停止操作——响应中包含原始 messageId
DUPLICATE_SEND_UNRESOLVED一封完全相同的邮件发送结果不明确重发前检查“已发送邮件”

如果某种失败能够证明邮件未送达——任何源自 4xx 的错误代码、429 错误或连接失败——系统会立即释放该记录,因此遭到拒绝后重发绝不会被拦截。其他所有情况(包括来自我们尚未遇到的提供方的错误代码)都会被标记为未决:错误地将邮件标记为未决,代价是拦截一次重发;错误地释放记录,则会让某人的收件箱收到重复邮件。

如需有意再次发送同一封邮件,请传入 allow_duplicate: true。这是一个无条件的单次请求绕过标记——如果重放调用也带有此标记,就会再次发送,因为该标记表示有人已决定发送这封邮件。强制发送尝试会与先前记录并存,而不会取而代之,因此即使覆盖操作遭到拒绝,原始投递仍会阻止普通重放。

记录按邮箱划分作用域:调用方提供 mailbox 时使用该值,否则使用提供方实例。运维人员可以通过 AGENT_EMAIL_DUPLICATE_SEND_WINDOW_MS 更改时间窗口(默认值为 900000);设为 0 可完全停用此防护机制。

账本保存在服务进程的内存中。它能防止实际会发生的重放——在运行中的服务内重试——但服务重启后记录不会保留。

软件包

软件包说明
@usejunior/email-core核心邮件操作、内容引擎、安全功能和提供方接口
@usejunior/email-mcpMCP 服务适配器、命令行工具和监视器
@usejunior/provider-microsoftMicrosoft Graph API 邮件提供方
@usejunior/provider-gmailGmail API 邮件提供方
email-agent-mcp分发封装(npx email-agent-mcp)
@usejunior/email-agent-mcp兼容性封装,与其他软件包同步发布;新安装请使用 email-agent-mcp

质量与可信度指标

  • 每次拉取请求和推送到 main 时都会运行 CI(在 Node 20 + 22 上执行 lint、类型检查和测试)
  • 使用 CodeQL 和 Semgrep 进行安全扫描
  • 在 Codecov 上发布覆盖率
  • 通过 npm run check:spec-coverage 强制执行 OpenSpec 可追溯性检查
  • 整个测试套件包含 300 多项测试
  • 维护者:Steven Obiajulu

架构

email-agent-mcp/
├── packages/
│   ├── email-core          Core actions, content engine, security
│   ├── email-mcp           MCP server adapter, CLI, watcher
│   ├── provider-microsoft  Microsoft Graph provider
│   ├── provider-gmail      Gmail API provider
│   └── email-agent-mcp         Distribution wrapper (npx entry point)
├── openspec/               Spec-driven development
└── scripts/                CI and validation scripts

发布

通过 GitHub Actions 采用基于标签的发布,并使用 npm OIDC 可信发布。所有 6 个软件包按依赖顺序使用 --provenance 发布,随后使用 mcp-publisher 将 server.json 发布到官方 MCP Registry。

常见问题

这与 Claude Code 兼容吗?

兼容。运行 npx email-agent-mcp 启动 MCP 服务,然后在 Claude Code 设置中进行配置。

Agent 能否在未获我许可的情况下发送电子邮件?

不能。默认情况下,发送允许列表为空。在你明确配置允许的收件人之前,Agent 无法发送任何电子邮件。

这会存储我的电子邮件凭据吗?

OAuth 令牌由 MSAL(Microsoft)管理,并存储在操作系统钥匙串或 ~/.email-agent-mcp/ 下的本地配置文件中。Agent Email 从不存储原始密码。

我可以连接多个邮箱吗?

可以。你可以同时配置 Microsoft 365 和 Gmail。读取操作默认使用主邮箱;配置了多个邮箱时,写入操作需要指定邮箱。

OpenClaw CLI 因“Unrecognized key: mcp”拒绝我的配置

OpenClaw CLI 和 macOS 应用的版本可能不同。应用(运行网关的应用)可能支持 CLI 尚不识别的配置键。更新 CLI:cd ~/Projects/NemoClaw && npm install openclaw@latest。或者,直接重启网关:launchctl kickstart -k gui/501/ai.openclaw.gateway。

监视器启动了,但找不到任何邮箱

邮箱凭据存储在 ~/.email-agent-mcp/tokens/ 中。如果此目录为空,请运行 npx email-agent-mcp 或 npm run dev:configure,通过 OAuth 进行身份验证。在至少配置一个邮箱之前,监视器会因没有可轮询的邮箱而退出。

OpenClaw 显示“Demo mode -- run email-agent-mcp configure to connect”

MCP 服务正在运行,但没有真实的邮箱凭据。运行 npx email-agent-mcp 完成交互式 OAuth 设置,然后重启 OpenClaw 网关,让 MCP 服务使用有效令牌重新连接。

我刚完成身份验证,一周后令牌却过期了

Microsoft 刷新令牌通常有效期为 90 天,但你的 Azure AD 租户可能会强制采用更短的有效期。代码使用带操作系统钥匙串持久化功能的 MSAL(@azure/identity-cache-persistence),可自动静默刷新令牌。如果 MSAL 返回 interaction_required 或 invalid_grant,请重新运行 npx email-agent-mcp 进行身份验证。常见原因包括:条件访问策略、要求重新验证 MFA,或管理员配置的令牌有效期策略。

OpenClaw Telegram 机器人收到消息,但没有回复

使用 openclaw status 确认 Telegram 通道运行正常。如果通道显示 OK,但没有收到回复,请检查:(1) 你的 Telegram 用户 ID 是否位于 openclaw.json 的 channels.telegram.allowFrom 中;(2) 是否存在匹配 channel: "telegram" 的绑定;(3) 配置更改后是否重启了网关。对于只有一个所有者的机器人,请使用 dmPolicy: "allowlist" 并明确设置 allowFrom ID,而不要依赖配对审批。

开发

npm ci
npm run build
npm run lint --workspaces --if-present
npm run test:run
npm run check:spec-coverage

另请参阅

隐私

Agent Email 完全在你的本地计算机上运行。电子邮件凭据存储在操作系统钥匙串(MSAL)和本地配置文件中。Agent Email 本身不会将任何电子邮件内容发送到外部服务。

治理

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。