Skip to main content
Glama
evilmordy

qqconnect

by evilmordy
README.md
# cn-mail-mcp

给任意 MCP 客户端用的 IMAP/SMTP 服务器,覆盖 QQ、163、126 和腾讯企业邮。默认**只读**。

授权码放在本机账号文件或 `.env`,不要写进 git,不要发给模型,不要出现在工具结果或日志里。

> 实验项目,不是各家官方邮箱连接器。Gmail / Outlook 请继续用官方连接器。安全问题走 [Private vulnerability reporting](https://github.com/evilmordy/cn-mail-mcp/security/advisories/new),不要在公开 issue 里贴授权码。

## 快速开始

需要 Node.js 22+ 和 pnpm。

```bash
pnpm install
pnpm build
```

### 获取 IMAP 授权码

第三方客户端不能使用网页登录密码,只要 IMAP **授权码**。

1. **QQ / Foxmail**:https://mail.qq.com → 设置 → 账号与安全 → 安全设置 → 开启 IMAP/SMTP → 生成授权码。
2. **163 / 126**:网页邮箱 → 设置 → POP3/SMTP/IMAP → 开启 IMAP → 按提示生成客户端授权码。163 登录后必须发 IMAP `ID`,本服务默认会发。
3. **腾讯企业邮**:开启 IMAP/SMTP 后使用客户端专用密码。主机为 `imap.exmail.qq.com:993` / `smtp.exmail.qq.com:465`。

更细的步骤见 [skills/mail-imap/SKILL.md](./skills/mail-imap/SKILL.md)。

### 最小配置

推荐先不把授权码写进客户端配置。把下面任一客户端配好并重启后,对助手说「绑定邮箱」。支持的客户端会:

1. 用 form elicitation 收集邮箱地址、备注、服务商(不含授权码);
2. 用 URL elicitation 打开只监听 `127.0.0.1` 的一次性页面,让你在浏览器里填写授权码;
3. 把授权码写入本机 `0600` 账号文件,登录 IMAP,只回报成功或失败。

账号文件默认在 `$XDG_CONFIG_HOME/cn-mail-mcp/accounts.json`,否则是 `~/.config/cn-mail-mcp/accounts.json`(Windows 为 `%APPDATA%\cn-mail-mcp\accounts.json`)。查看路径:`node dist/index.js accounts path`。

若客户端没有对应的 elicitation 能力,助手会给出手动步骤。你也可以自己做:

```bash
cp .env.example .env
# 编辑 .env:MAIL_USER 与 MAIL_AUTH_CODE,等号两边不要空格
pnpm check
```

`pnpm check` 只在运行命令的这台机器上登录 IMAP,然后退出。成功说明这台机器和授权码可用。

终端交互绑定(授权码只在终端输入,不要贴进对话):

```bash
node dist/index.js accounts add
node dist/index.js accounts list
node dist/index.js --check
```

## 客户端配置

把 `/ABS/PATH/cn-mail-mcp` 换成仓库绝对路径。配置里不要写授权码。

### Cursor

文件:项目 `.cursor/mcp.json`,或全局 `~/.cursor/mcp.json`。

stdio 字段以官方说明为准:`type` 必填,另有 `command`、`args`、`env`、`envFile`([Cursor MCP](https://cursor.com/docs/mcp))。

```json
{
  "mcpServers": {
    "cn-mail-mcp": {
      "type": "stdio",
      "command": "node",
      "args": ["/ABS/PATH/cn-mail-mcp/dist/index.js"],
      "envFile": "${workspaceFolder}/.env"
    }
  }
}
```

`envFile` 只在你打算用 `.env` 时需要。只用本机账号文件时可以删掉这一行。

### VS Code

文件:工作区 `.vscode/mcp.json`(用户级用命令面板 “MCP: Open User Configuration”)。顶层键是 `servers`,stdio 的 `type` 必填([VS Code MCP configuration](https://code.visualstudio.com/docs/agents/reference/mcp-configuration))。

```json
{
  "servers": {
    "cn-mail-mcp": {
      "type": "stdio",
      "command": "node",
      "args": ["/ABS/PATH/cn-mail-mcp/dist/index.js"],
      "envFile": "${workspaceFolder}/.env"
    }
  }
}
```

### Claude Desktop

官方快速开始使用 `mcpServers` + `command` + `args`,示例里没有 `type`([Connect to local MCP servers](https://modelcontextprotocol.io/quickstart/user))。配置文件:

- macOS:`~/Library/Application Support/Claude/claude_desktop_config.json`
- Windows:`%APPDATA%\Claude\claude_desktop_config.json`

改完后完全退出并重启 Claude Desktop。不要把授权码写进这个 JSON。

```json
{
  "mcpServers": {
    "cn-mail-mcp": {
      "command": "node",
      "args": ["/ABS/PATH/cn-mail-mcp/dist/index.js"]
    }
  }
}
```

### 通用 stdio

与 Claude Desktop 相同的 `mcpServers` 形状,适用于其他本地 stdio 客户端:

```json
{
  "mcpServers": {
    "cn-mail-mcp": {
      "command": "node",
      "args": ["/ABS/PATH/cn-mail-mcp/dist/index.js"]
    }
  }
}
```

stdout 只走 MCP JSON-RPC。日志在 stderr。

## 多账号

再绑第 2、第 3 个邮箱:再调用一次 `add_mailbox`,或在终端运行 `accounts add`。

手动 `.env` 时用后缀 `_2`、`_3`:

```
MAIL_USER=me@qq.com
MAIL_AUTH_CODE=
MAIL_USER_2=work@163.com
MAIL_AUTH_CODE_2=
MAIL_ACCOUNT_ID_2=work
```

`list_accounts` 只返回 id、地址、服务商和来源,不含授权码。多个邮箱时,后续工具要带 `account_id`。

解绑:`unbind_mailbox`,或 `node dist/index.js accounts unbind <account_id>`。这只解除本机绑定,不删除服务器上的邮件。

JSON 多账号仍可用 `CN_MAIL_MCP_ACCOUNTS`,但必须用 `authCodeEnv` 指向环境变量,不能内联 `authCode`。

## 工具

| 工具 | 作用 |
|---|---|
| `add_mailbox` | 绑定邮箱。禁止向用户索取授权码 |
| `list_accounts` | 列出已绑定邮箱,不含授权码 |
| `unbind_mailbox` | 解除绑定,不删服务器邮件 |
| `verify_mailboxes` | 登录检查,只回报成功或失败 |
| `list_folders` / `search_messages` | 列文件夹 / 按信封搜索 |
| `get_message` | 读一封。正文在 `<untrusted-email>` 里,`BODY.PEEK` 不标已读 |
| `list_attachments` / `get_attachment` | 附件元数据 / 按白名单下载(最大 2 MiB) |
| `save_draft` / `save_reply_draft` | 草稿。需要档位 `draft` 或 `send` |
| `send_email` / `send_reply` / `send_forward` / `send_draft` | 先返回预览和 `confirm_token`,用户同意后再带 token 发送 |
| `get_settings` / `set_settings` | 查看或修改档位。打开 `send` 或 `allow_sensitive` 需要确认 |

档位在 `.cn-mail-mcp.json`(示例见 [.cn-mail-mcp.example.json](./.cn-mail-mcp.example.json)),不要写进 `.env`。默认 `read`。打开发送:

```bash
node dist/index.js config set-mode send --allow you@qq.com
```

或让助手调用 `set_settings`。`mode=send` 必须带非空白名单,并且先经过用户可见的确认。第一次 `send_*` 不发信,只给出预览;用户明确同意后,第二次调用才带 `confirm_token` 走 SMTP。

## 安全

- 默认只读。删除、移动、改旗标都没有实现。
- 正文是不可信数据。验证码 / 重置类邮件显示为 `[redacted:otp]`,正文不会下载。
- 读信使用 `BODY.PEEK`,文件夹以 `EXAMINE` 只读打开。
- 发送默认关闭。需要档位 `send`、收件人白名单,以及预览确认。不接受去掉发信确认的改动。
- 授权码、网页密码不要进入 git、模型上下文、工具结果或日志。

细节见 [SECURITY.md](./SECURITY.md)。绑定流程如何对应 MCP 规范见 [docs/onboarding.md](./docs/onboarding.md)。

## 故障排除

- **`pnpm check` 认证失败**:授权码不要带空格;网页里 IMAP 须开启;改过登录密码后要重新生成授权码。
- **163 `Unsafe Login`**:确认授权码是新的。不要改用 POP3。
- **没有预设主机**:地址不是 QQ / 163 / 126 / 企业邮时,在 `.env` 里设置公网 `MAIL_HOST`(993)和 `MAIL_SMTP_HOST`(465)。内网和云元数据地址会被拒绝。
- **工具列表对不上**:看 `get_settings` 的 `server.needs_restart`。为真就停掉再启动 cn-mail-mcp。
- **改了 `.env` 仍提示没配置**:文件要叫 `.env`,等号两边不要空格。已经在环境里的同名变量不会被文件覆盖。`list_accounts` 会重新读 `.env`。

## 限制

客户端能不能在对话之外安全收下授权码,取决于它有没有声明 MCP elicitation 的 `url` 模式(`form` 按规范不能用来收集授权码)。托管或云端环境可能拦截 IMAP `993` 和 SMTP `465`;可选的本机回环 HTTP CONNECT 代理(`CN_MAIL_MCP_MAIL_PROXY`)只有在代理自己能到达这两个端口时才有用,它不会把 IMAP 改到 `443`。

## 开发

```bash
pnpm typecheck
pnpm test
pnpm knip
```

`pnpm test` 使用假邮箱后端,不登录真 IMAP。真登录用本地 `pnpm check`。

TDQS

A3.9/5.0

Scored across 15 tools

Disambiguation5/5

Each tool targets a distinct email operation: settings, mailbox binding, draft creation, sending, searching, reading, and attachments. The four send variants and two draft savers are clearly differentiated by their descriptions and recipient/behavior rules.

Naming Consistency5/5

All 15 tools follow a consistent snake_case verb_noun pattern, such as get_settings, save_draft, send_reply, and list_folders. The get_ versus list_ distinction is also semantically regular: singular resources use get_, collections use list_.

Tool Count5/5

15 tools is at the upper bound of well-scoped, but each tool represents a meaningful email operation. The count is justified by the breadth of composing, sending, reading, searching, and attachment handling.

Completeness2/5

The set has a significant gap: both get_settings and list_accounts explicitly direct users to an add_mailbox tool that is not present, so mailbox onboarding cannot be completed. Additional message lifecycle operations like move/delete are absent as well, but the missing referenced tool is the critical failure.

Maintenance

ActivityMaintained
ResponsivenessNo issues