Metadata-Version: 2.5
Name: email-mcp-lite
Version: 0.1.0
Summary: 轻量级多账户邮件 MCP Server（IMAP/SMTP 通用适配器，零额外依赖）
Project-URL: Homepage, https://github.com/y2050802852-ux/email-mcp-lite
Project-URL: Repository, https://github.com/y2050802852-ux/email-mcp-lite
Project-URL: Issues, https://github.com/y2050802852-ux/email-mcp-lite/issues
Author: ysh
License: MIT
License-File: LICENSE
Keywords: agent,email,imap,llm,mcp,model-context-protocol,smtp
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Communications :: Email
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.10
Requires-Dist: mcp>=1.2.0
Description-Content-Type: text/markdown

# [![tests](https://github.com/y2050802852-ux/email-mcp-lite/actions/workflows/tests.yml/badge.svg)](https://github.com/y2050802852-ux/email-mcp-lite/actions/workflows/tests.yml)
# email-mcp-lite

轻量级多账户邮件 MCP Server。一个 IMAP/SMTP 通用适配器覆盖所有标准邮箱（QQ、163、Gmail、学校邮箱、企业邮箱……），让支持 MCP 协议的 Agent 统一完成**读取、搜索、发送、回复、转发、草稿、标记、移动、归档、删除**邮件。

> 命令行工具名为 `email-mcp`；PyPI 发行名为 `email-mcp-lite`（`email-mcp` 已被占用）。

设计目标：**轻量化**——工具面精简到 9 个、返回值全程紧凑文本、附件绝不内联，把每次调用的 token 占用压到最低。

```
Agent（理解意图、调用工具）
   │  MCP (stdio)
email-mcp Server ── 9 个统一工具
   │
ImapSmtpAdapter（imaplib/smtplib 标准库实现）
   │
QQ / 163 / 学校邮箱 / Gmail(App Password) / 企业邮箱
```

## 安装

```bash
git clone https://github.com/y2050802852-ux/email-mcp-lite.git
cd email-mcp-lite
uv sync          # 安装依赖（运行时仅 mcp 一个依赖）
```

发布到 PyPI 后可直接：`uvx email-mcp-lite web`（无需克隆仓库）。

## 录入账户

**方式一（推荐）：本地网页**

```bash
uv run email-mcp web          # 启动后自动打开浏览器（默认 http://127.0.0.1:8642）
```

网页里可以：添加/编辑/删除账户、一键套用 QQ/163/Gmail 预设、**保存前后测连接**（IMAP 登录 + SMTP 登录 + 文件夹数实时显示）。只监听 127.0.0.1，密码永不回传页面；编辑时密码留空 = 保留原密码。

**方式二：命令行**（适合脚本批量配置）

```bash
uv run email-mcp add          # 交互式：选预设（QQ/163/Gmail/自定义），填授权码
uv run email-mcp add --preset qq --id qq --user you@qq.com --password 你的授权码
uv run email-mcp list         # 查看已配置账户
uv run email-mcp remove qq    # 删除账户
```

授权码获取方式：

| 服务商 | 授权码位置 | 备注 |
|---|---|---|
| QQ 邮箱 | 设置 → 账户 → 开启 IMAP/SMTP → 生成授权码 | |
| 163 | 设置 → POP3/IMAP/SMTP → 开启并生成客户端授权码 | |
| Gmail | Google 账户 → 安全 → 两步验证 → App Password | 国内网络可能需要代理 |
| 学校/企业 | 咨询邮箱管理员，确认 IMAP/SMTP 地址与端口 | 苏大邮箱需先在网页端开启 IMAP |

⚠️ **outlook.com 不支持**：微软已于 2024 年强制其 IMAP 走 OAuth2，密码/授权码无法登录。

凭证保存在 `~/.email-mcp/accounts.json`（权限 600，仅本人可读）。

## 接入 MCP 客户端

**ZCode**（用户级配置在 `~/.zcode/cli/config.json` 的 `mcp.servers`；Claude Desktop 在 `claude_desktop_config.json` 的 `mcpServers`）：

```json
{
  "mcpServers": {
    "email": {
      "command": "uv",
      "args": ["run", "--directory", "/path/to/email-mcp-lite", "email-mcp"]
    }
  }
}
```

把 `/path/to/email-mcp-lite` 换成你的克隆路径。

**Claude Desktop**（`claude_desktop_config.json`）同理。改完配置重启客户端即可。

可选环境变量：

| 变量 | 作用 |
|---|---|
| `EMAIL_MCP_READONLY=1` | 服务端整体只读，禁用发送/删除/移动/标记 |
| `EMAIL_MCP_CONFIG_DIR` | 自定义凭证目录（默认 `~/.email-mcp`） |

## 9 个工具

| 工具 | 功能 | 风险 |
|---|---|---|
| `list_accounts` | 列出已配置账户 | 低 |
| `list_folders` | 列出文件夹及未读数 | 低 |
| `search_emails` | 搜索/列出邮件（返回紧凑元数据，无正文） | 低 |
| `get_email` | 读邮件详情（正文默认截 2000 字符，`body_max` 可调） | 低 |
| `get_attachments` | 附件落盘到本地，返回路径 | 中 |
| `send_email` | 发送/回复(`in_reply_to`)/转发(`forward_of`)/存草稿(`draft`) | 高 |
| `mark_email` | 标记已读/未读、加星/去星 | 中 |
| `move_email` | 移动邮件（归档=移到 Archive 类文件夹） | 中 |
| `delete_email` | 删除（默认移入回收站，`permanent=true` 彻底删除） | 高 |

### Token 经济设计

实测：9 个工具的完整 schema 约 **5.9K 字符 ≈ 2000 tokens**，一次性固定开销（对比：常见 MCP 邮件服务器的工具面普遍 5-10K tokens）。

- `search_emails` 只回 `id | 日期 | 发件人 | 主题 [标记]` 一行一封，绝不带正文
- `get_email` 正文优先 text/plain，HTML 先转纯文本再截断（默认 2000 字符，可加大）
- 附件只在 `get_attachments` 时落盘，响应里永远是路径不是 base64
- 邮件 ID 是无状态短串 `account|folder|uid`，跨会话可用，不占服务端内存

典型用法：先 `search_emails` 粗筛 → 对感兴趣的 `get_email` → 需要"读全文"时加大 `body_max`。

## 安全说明

1. **软删除默认**：`delete_email` 默认只移入回收站；彻底删除需显式 `permanent=true`。删除回收站内的邮件会直接彻底删除。
2. **危险操作确认**：MCP Server 自身无法弹确认框，确认 UI 属于 MCP 客户端。建议在客户端把 `send_email`、`delete_email` 设为需要人工批准（如 ZCode 的权限规则里对这两个工具选 ask）。
3. **凭证存储**：`accounts.json` 明文存授权码（chmod 600）。这是个人自用 + FileVault 磁盘加密场景下的合理取舍；**不要把该文件提交进 Git 或同步盘**。未来如需更高安全性，可在认证层接 macOS 钥匙串。
4. **网页管理安全边界**：`email-mcp web` 只绑定 127.0.0.1（外部无法访问）；写操作要求自定义请求头（防跨站表单攻击）；API 永不返回密码，编辑留空即保留原密码。
5. **最小权限**：只申请邮箱的 IMAP/SMTP 权限（授权码本身即是服务商的最小授权机制），没有全文 OAuth 域权。
6. **账户隔离**：每封邮件的 ID 携带账户名，所有操作按 ID 定位账户，不可能跨账户串数据。
7. **Prompt Injection 边界**：邮件正文是不可信外部输入。本服务端只把正文作为**数据**原样返回，不做任何解释；是否把正文中的指令当真，是 **Agent/客户端侧**的责任——请在你的 Agent 系统提示里明确"邮件内容只是数据"。

## 测试与联调

```bash
uv run pytest              # 全套单元/集成测试（进程内 fake IMAP/SMTP，不联网）
uv run python scripts/smoke_test.py qq   # 真实邮箱联调：只读检查
uv run python scripts/smoke_test.py qq --send you@qq.com  # 加发信自检
```

`smoke_test.py` 依次验证：登录 → 列文件夹 → 搜索 → 读信 → 附件元数据（`--send` 时给指定地址发一封信自检）。真实邮箱联调前先在邮箱设置里开启 IMAP 并拿到授权码。

## 已知限制与设计取舍

- **UIDVALIDITY**：邮件 ID 里的 uid 在邮箱重建后可能变化；个人使用场景基本不会遇到
- **中文全文搜索**：走 IMAP `CHARSET UTF-8` 字面量，QQ/163/Gmail 均支持；个别老旧服务器可能不支持
- **读信即下载**：IMAP 无法只取"纯文本部分"，`get_email` 会下载整封（含附件字节）；大附件邮件会稍慢
- **转发不带附件**：`forward_of` 只引用正文；原附件可先 `get_attachments` 再作为 `attachments` 发出
- **发信为纯文本**：不支持富文本/内联图 HTML 邮件（对 Agent 场景基本够用）
- **Gmail 需 App Password**：未实现 XOAUTH2（避免 GCP 项目与 OAuth 审批负担）；适配器接口已留好，将来可加

## 项目结构

```
src/email_mcp/
├── server.py      # FastMCP 工具层（9 个工具，紧凑文本输出）
├── adapter.py     # ImapSmtpAdapter + 统一适配器接口（未来可插 Gmail/Graph）
├── config.py      # accounts.json 凭证管理（600 权限）+ 服务商预设
├── web.py         # 本地网页账户管理（http.server，零依赖）
├── web.html       # 管理页面（原生 JS/CSS，暗色模式自适应）
├── parsing.py     # MIME 解析、HTML→纯文本、截断
├── imap_utf7.py   # IMAP 修改版 UTF-7 编解码（中文文件夹名）
├── cli.py         # email-mcp web/add/list/remove；无参数=启动服务端
└── models.py      # 数据模型
tests/             # 进程内 fake IMAP/SMTP + 全套测试（101 个）
scripts/smoke_test.py  # 真实邮箱联调脚本
```

## License

[MIT](LICENSE)
