关于 your-mail-mcp
your-mail-mcp 是可自托管的只读 MCP 服务,将 IMAP 邮箱镜像到本地,并用 notmuch 建立索引。它为 AI 助手和 MCP 客户端提供搜索与邮件读取工具,但无法发送、删除或移动邮件。
主要功能
- 01本地 IMAP 邮件镜像
- 02notmuch 全文索引
- 03跨账户搜索
- 04只读邮件及附件访问
- 05同步状态与刷新工具
适用场景
- 01查找旧邮件中的预订信息
- 02梳理邮件往来与承诺
- 03汇总需要处理的新邮件
- 04将客户需求带入工作会话
MCP 相关
该服务提供 11 个只读工具,用于搜索、查看邮件及检查索引邮件的状态。MCP 客户端可通过本地 stdio 或带 OAuth 的 HTTPS 连接。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
docker run -i --rm -e PUBLIC_URL -e OAUTH_PASSPHRASE ghcr.io/wildsurfer/your-mail-mcp:0.5.0PUBLIC_URLPublic base URL the server is reached at (used for OAuth metadata)OAUTH_PASSPHRASE密钥Passphrase gating the OAuth consent step本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。
ghcr.io/wildsurfer/your-mail-mcp:0.5.0Streamable HTTPstdio工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
your-mail-mcp
你的邮件里早已有了答案:预订编号、门禁密码、发票、保修期,以及人们通过书面形式作出的承诺。这个 MCP 服务可以让你的 AI 助手找到这些信息,而且只能读取。
可以这样向它提问:
- “找到 6 月渡轮的预订编号。”
- “去年夏天酒店发来的 Wi-Fi 密码是什么?”
- “会计师关于增值税回复了什么,什么时候回复的?”
- “按顺序整理我和建筑商关于屋顶的所有邮件,并总结谁承诺了什么。”
- “今天早上,我的所有账户里收到了哪些真正需要我处理的邮件?”
适用于:
- 理解问题的搜索。 对你的全部历史邮件进行全文搜索,将每个账户纳入同一个索引,并按照你的思路提问。
- 用手机筛选邮件。 无论身在何处,都能查看隔夜收到的邮件晨间摘要,其中垃圾邮件已预先过滤。
- 将邮件作为其他工作的上下文。 从邮件往来中提取客户需求,带入你的编码或写作会话。
- 可以持续运行的 Agent。 这个进程没有发送、删除或移动邮件的途径。即使恶意邮件到达你的助手,也只会被读取,仅此而已。定时摘要和始终在线的 Agent 都可以放心运行。
只需两个文件,然后运行 docker compose up -d 即可完成设置。参见快速入门。
工作原理
这是一个可自托管的 MCP 服务。它通过 mbsync 将一个或多个 IMAP 账户镜像到本地 maildir,使用 notmuch 为邮件建立索引,并根据该索引响应工具调用。Claude 和 ChatGPT 应用通过 HTTPS 和 OAuth 连接;Claude Code、Codex、Cursor 和 Claude Desktop 则在同一台机器上通过 stdio 连接。任何 MCP 客户端都能使用。如果你希望充分保护隐私,可以连接一个由本地大模型支持的客户端,这样邮件就永远不会离开你的机器。

在图中,邮件始终只从左向右流动。根据配置,镜像只会拉取邮件。Go 代码向提供商发起的唯一连接是每个账户一次 IMAP LIST,用于了解服务器如何命名其垃圾邮件和废纸篓文件夹;它从不选择邮箱,也从不获取邮件。安全性部分列出了该进程无法执行的所有操作。图表源文件位于
docs/diagrams/how-it-works.html。
快速开始
在你的机器上,为你的机器服务。唯一的要求是 Docker;ghcr.io/wildsurfer/your-mail-mcp 中的镜像由 CI 为 amd64 和 arm64 构建。
mkdir your-mail && cd your-mail
curl -fsSLO https://raw.githubusercontent.com/wildsurfer/your-mail-mcp/main/compose.yaml
curl -fsSL https://raw.githubusercontent.com/wildsurfer/your-mail-mcp/main/accounts.example.json -o accounts.json
将你的账户填入 accounts.json。${WORK_PASS} 会从环境变量中替换,因此文件本身不包含密码:
{
"accounts": [
{ "name": "work", "host": "imap.gmail.com", "user": "[email protected]", "password": "${WORK_PASS}" },
{ "name": "personal", "host": "imap.mail.me.com", "user": "you", "password": "${PERSONAL_PASS}" }
]
}
将密码放入与 compose.yaml 同目录的 .env 中:
# .env
WORK_PASS=your-gmail-app-password
PERSONAL_PASS=your-icloud-app-specific-password
compose.yaml 会将 WORK_PASS 和 PERSONAL_PASS 传入容器。使用其他变量名的账户,也需要在其中的 environment: 下添加该变量名。
有两项提供商相关的细节最容易让人耗费时间。Gmail 通过 IMAP 仅接受应用专用密码,而且必须先开启两步验证才能使用应用专用密码。iCloud 要求将 @icloud.com 前面的短名称作为 user;完整地址会导致登录失败。文件中的所有键都列在参考文档中。
这两个文件存放着你的邮件密码。请勿将此目录纳入版本控制,也不要将其备份到离开本机的位置。如果你不希望这样做,可以为账户指定 pass_cmd,而不是 password:使用一个能输出密钥的命令,例如,Docker 密钥可使用 cat /run/secrets/work_pass,Mac 上则可使用 security find-generic-password -s your-mail -a work -w。mbsync 会在连接时运行该命令,密码不会存储在磁盘或环境变量中。请参阅参考文档。
docker compose up -d
docker compose logs -f # watch the first sync
今天 INBOX 中的邮件会在几分钟内变得可搜索。完整历史记录会按照提供商允许的速度逐步同步,而 status 工具会报告同步进度。大型 Gmail 账户可能需要数天,因为 Google 将 IMAP 下载量限制在每天约 2.5GB;首次镜像时,请在 .env 中设置 SYNC_TIMEOUT=8h。提供商说明中有详细信息。
然后连接客户端。Claude Code:
claude mcp add your-mail -- docker exec -i your-mail-mcp your-mail-mcp stdio
启动服务栈后,Cursor 和 VS Code 只需单击一下即可添加:
Claude Desktop、Cursor、Codex 和其他 stdio 客户端
任何以命令方式启动 MCP 服务的客户端:
{ "command": "docker", "args": ["exec", "-i", "your-mail-mcp", "your-mail-mcp", "stdio"] }
每个会话都是通往运行中容器的桥梁,因此所有客户端看到的都是同一索引和同一同步进度。关闭客户端,会话也会随之结束。
Claude Code 还可以将其作为插件接入,这会添加服务以及一个了解查询语法的 email 技能:
/plugin marketplace add wildsurfer/your-mail-mcp
/plugin install your-mail@your-mail-mcp
如果没有运行中的服务栈,
docker run -i --rm --env-file .env -v index:/index -v mail:/mail -v ./accounts.json:/config/accounts.json:ro ghcr.io/wildsurfer/your-mail-mcp
会启动一个守护进程,并在单个会话期间运行。临时体验一下没问题;如果想让内容保持最新,请使用 compose。
Claude 和 ChatGPT 的智能手机应用通过各自供应商的服务器访问连接器,因此服务器需要一个公开的 HTTPS 地址。隧道可以提供这样的地址:隧道主动向外发起连接,家庭网络上没有任何端口处于监听状态,邮件仍保留在你的设备上。
安装 Tailscale 后,只需运行一条命令,macOS 和 Linux 上相同:
tailscale funnel --bg 8080
命令会输出类似 https://your-machine.your-tailnet.ts.net 的主机名,--bg 会让它在重启后继续运行。将该主机名和一个密码短语一起写入 .env,然后重启:
# .env
PUBLIC_URL=https://your-machine.your-tailnet.ts.net
OAUTH_PASSPHRASE=pick-a-long-one-you-can-type-on-a-smartphone
docker compose up -d
OAUTH_PASSPHRASE 是互联网和你的邮件之间唯一的凭据。每次猜错都要花一秒钟,而且尝试会串行处理,但这两点都无法弥补密码短语过短的问题。请使用足够长、但仍能在手机上输入的密码短语。
Funnel 需要 HTTPS 证书,并且需要为你的 tailnet 启用 Funnel 节点属性;首次运行时,CLI 会询问是否添加策略行。tailscale funnel status 会显示公开了哪些内容,而 tailscale funnel --https=443 off 则会关闭隧道。
现在添加连接器。Claude 和 ChatGPT 的智能手机应用都无法添加连接器,因此你需要在网页版添加一次,之后它就会显示在手机上。
- 在 claude.ai 或 Claude Desktop 中,打开 设置 → 连接器,然后添加自定义连接器。
- 为其命名,并将 URL 设为
<PUBLIC_URL>/mcp。高级 OAuth 字段留空;服务器会自行注册客户端。 - Claude 会打开授权页面。输入你的
OAUTH_PASSPHRASE。 - 打开手机上的 Claude 应用。连接器已在其中;在对话中打开撰写框的工具菜单即可启用它。
PUBLIC_URL 必须与你在客户端中输入的内容完全一致。服务器会在其 OAuth 元数据中将 PUBLIC_URL + /mcp 发布为 resource,这里不匹配是连接器无法添加的最常见原因。
使用 Cloudflare Tunnel 代替 Tailscale,并使用自己的域名
如果要使用你拥有的域名下的主机名,请按此操作。下方的 mail.example.com 必须是你自己的域名,并且已添加到你的 Cloudflare 账户中;Cloudflare 不会为已命名的隧道提供主机名。
cloudflared tunnel login
cloudflared tunnel create your-mail
create 会输出隧道的 UUID 和其写入的凭据文件路径;如果找不到 UUID,cloudflared tunnel list 会再次显示它。为主机名设置路由,然后写入 ~/.cloudflared/config.yml:
cloudflared tunnel route dns your-mail mail.example.com
tunnel: your-mail
credentials-file: /Users/you/.cloudflared/f9e2….json # the path create printed
url: http://localhost:8080
cloudflared tunnel run your-mail
要让它持续运行:在 Linux 上运行 sudo cloudflared service install。在 macOS 上,通过 Homebrew 安装并使用 brew services start cloudflared,因为 sudo 安装路径会在 root 用户的主目录中查找证书,而那里没有 cloudflared tunnel login 写入你主目录的证书。
然后在 .env 中设置 PUBLIC_URL=https://mail.example.com,并运行 docker compose up -d。
ChatGPT,以及从另一台设备使用 Claude Code 或 Codex
ChatGPT。 自定义 MCP 连接器需要通过开发者模式使用,该模式要求拥有 Pro、Plus、Business、Enterprise 或 Education 账户,并且仅在网页版提供。
- 在网页版 ChatGPT 中,打开 设置 → 安全与登录,然后启用开发者模式。对于 Business 和 Enterprise 工作区,管理员可能需要先允许启用该模式。
- 添加远程 MCP 服务连接器,将 URL 设为
<PUBLIC_URL>/mcp,并选择 OAuth 作为身份验证方式。ChatGPT 支持动态客户端注册,因此无需粘贴任何内容。 - 在授权页面输入你的
OAUTH_PASSPHRASE并批准。 - 打开手机上的 ChatGPT,并在聊天中启用连接器。
这些菜单的位置可能会变。如果你看到的名称与上述不一致,请在设置中查找开发者模式,然后找到通过 URL 添加连接器的位置。ChatGPT 会在移动端禁用某些 MCP 写入操作;不过这不会影响这里,因为此服务器不提供此类操作。
Claude Code:
claude mcp add --transport http your-mail https://your-host/mcp
Codex:
codex mcp add your-mail --url https://your-host/mcp
codex mcp login your-mail
如果你希望镜像在自己的设备开机与否的情况下都能保持运行,请选择此方案。 每月需要花费几美元,同时有一个实际的取舍:邮件的完整明文副本会移到租用的磁盘上,应用密码也存放在旁边。安装步骤是在快速入门的基础上再加上隧道,运行在别人的计算机上;在存放邮件之前,还需要加固这台机器。两项说明都在 docs/server.md 中。
工具
共 11 个工具,全部为只读:
| 工具 | 功能 |
|---|---|
search | 搜索邮件。以 JSON 格式返回邮件会话摘要。 |
ids | 返回匹配查询的邮件 ID。 |
files | 返回匹配查询的 maildir 文件路径。 |
count | 统计匹配查询的邮件数量。 |
show | 显示一封邮件:以 JSON 格式返回邮件头和解码后的正文。 |
thread | 显示包含某封邮件的整个会话。默认排除垃圾邮件和废纸篓中的回复;设置 include_excluded 可将其包括在内。 |
text | 返回一封邮件的纯文本正文,并转换 HTML。 |
folders | 列出账户、各自的文件夹、索引标签,以及每个账户上次同步时间和上次错误。 |
refresh | 立即同步一个账户或所有账户的每个文件夹,然后重新建立索引。最多等待 20 秒;如果同步仍在运行,会予以说明。 |
status | 显示各账户的同步状态:首次同步是否完成、上次同步时间、已索引邮件数、错误和退避状态。 |
attachment | 根据 show 返回的部分编号,获取邮件的一个附件或 MIME 部分。图片以内嵌方式显示,文本(包括 JSON 和 XML)以标记文本块显示,其他二进制文件则返回签名下载链接。 |
search、ids、files 和 count 接受 notmuch 查询(from:、to:、
subject:、tag:、folder:、date:2026-01-01..2026-06-30,可组合使用
and/or/not),可选的 account 参数用于限定某个账户,还可通过
include_excluded 包括垃圾邮件和废纸篓中的邮件。系统通过 RFC 6154 SPECIAL-USE
为每个账户识别垃圾邮件和废纸篓文件夹,因此无论这些文件夹叫什么名称、使用哪种
语言,都能正确排除。当某个账户的镜像仍在填充时,这四个工具会在结果前添加说明,标出账户名称和目前已索引的邮件数量。
show 和 thread 会列出附件;attachment 工具则一次提供一个部分:不超过 5MB 的图片以内嵌方式显示,文本部分以标记文本显示,其他二进制文件则提供指向
GET /attachment/{id}/{part} 的短时有效签名链接(在此处也可使用 bearer token)。如果未启用 HTTP 监听器,超大二进制文件会保存到 /index/attachments/ 下,工具会返回可供 docker cp 使用的路径。该目录上限为 1GB;空间不足时优先删除最旧的文件。
为什么不选其他方案
GitHub 上大约有四十个电子邮件 MCP 服务。几乎所有服务都会实时连接 IMAP,并提供发送功能,而这与本服务立足的两项选择恰恰相反。有两个方案值得一提。
igor47/notmuchproxy 是最接近的现有方案,也是本服务采用当前设计的主要原因之一。它读取由你自行保持最新的 notmuch 存档,没有写入路径,并支持持有者令牌或完整的 OIDC。它的查询验证会拒绝未知前缀并给出说明,本服务在此将其重新实现为 validateQuery。两者有两点不同:它假设你已经运行 mbsync 和 notmuch,而本服务会生成 mbsync 配置、并行同步所有账户,并通过 IMAP 发现垃圾邮件和废纸篓;此外,它没有 account 参数。如果你已经在使用满意的 notmuch 配置,notmuchproxy 部署起来更简单,你应该选择它,而不是本服务。
hgn/mcp-server-notmuch 仅支持 stdio,因此只能由一台机器上的一个客户端使用;在本次调查中,它对不可信内容的处理是最好的。本服务的单一 render() 关口会在同一处标记邮件文本的每个字节,确保不会有任何单独的工具遗漏这一步,这一设计源自它的 render.py。
完整的调查结果,包括哪些说法是查阅源码后确认的,哪些取自 README,详见
docs/research/email-mcp-landscape.md。
安全性
在将此工具连接到你在意的邮箱前,请先阅读此部分。
它无法写入。 为每个账户生成的 mbsync 配置都带有 Sync Pull、Create Near、Remove Near 和 Expunge None(对于设置了 expunge_local 的账户,则为 Expunge Near,仅删除本地文件),且程序会自行写入该文件,因此无法通过编辑配置将其改为推送。Remove Near 只作用于本地:当服务器上的文件夹被删除或重命名时,其本地副本会连同其中的所有邮件一起保留,只有空的本地文件夹才会被删除。
Go 代码中唯一的 IMAP 操作是 LIST,程序会在启动时以及每小时按账户执行一次,以查找垃圾邮件和废纸篓文件夹;手动设置了 exclude_folders 的账户甚至会跳过此操作。该进程没有任何路径可以发送、删除、移动或标记邮件,其中也没有任何内容持有对账户的写入权限。
已删除的邮件仍保留在镜像中。 你在服务器上删除的邮件会保留在磁盘上,并通过 notmuch 的 deleted 标签从搜索结果中隐藏。对某个账户设置 expunge_local: true,即可物理删除这些本地副本。账户仍然绝不会被写入,但镜像也就不再是备份:远程消失的内容会在下一次同步时从本地消失。
目前的验证程度。 一位作者、一位操作者、三个真实账户:一个 iCloud 账户和两个 Gmail 账户。没有第三方安全审查,也没有其他人部署过它。与此相比,notmuchproxy 虽然只有零颗星,但其生产环境使用情况更有说服力。
密码以明文形式存放在容器中。 账户密码来自环境变量,并会在启动时写入生成的 mbsync 配置文件,该文件的权限模式为 0600。该文件未加密。任何能够读取容器环境或该文件的对象都能读取密码。如果账户配置了 pass_cmd,则密钥会保存在该命令读取的任何位置,例如 Docker 密钥或密钥链中;环境和生成的文件中只会保存该命令。不过,进程仍会在内存中接收密码,以便自行执行一次 IMAP LIST 操作。磁盘加密、谁可以进入容器执行命令,以及对主机的访问权限,均由操作者负责;本服务不声称会对静态存储的凭据进行加密。
一个密码短语,一次授权。 OAUTH_PASSPHRASE 使用恒定时间进行校验,并通过一个共享密钥控制整个服务。它不是按用户区分的凭据系统,任何持有该密码短语的人都能看到整个邮箱。它不会对静态存储的任何内容进行加密。请像保护邮件密码一样妥善保管它。
邮箱是秘密存储库。 密码重置、登录验证码和魔法链接都会通过邮件送达,因此,仅有读取权限就足以在这些内容落入不当之手或错误的 AI 会话时接管账户。只读设计和不可信内容标记移除了写入路径和指令渠道,但并不能让邮件内容变得无害。请只连接你信任的客户端。需要独立收件箱的 Agent 工作流必须使用独立邮箱地址;这需要使用其他工具。
已知问题。 search 的会话摘要会包含匹配会话中每封邮件的显示名称,而该名称由发件人控制。默认排除的文件夹(垃圾邮件、废纸篓)中的邮件仍可能通过这种方式,将攻击者指定的名称显示在你面前,尽管其正文不会显示。thread 和 show 不受此问题影响。本版本尚未修复此问题。
对于面向互联网的服务, docs/server.md 按各项加固措施的收益大小顺序列出了步骤。
参考
- 账户文件:每个键及其默认值。
- 环境变量:同步间隔和超时时间、监听地址、
INIT_MIRROR。 - 服务提供商说明:iCloud、Gmail、Dovecot。
- 故障排除:启动时的拒绝原因,以及有时为何不会排除垃圾邮件。
- 不使用 Docker:发布二进制文件及其调用的命令。
- 在服务上运行:安装脚本、安全加固,以及使用 Caddy 配置自己的域名。
- 从 0.4.x 升级。
- 设计规范和电子邮件 MCP 服务调查。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。