内容
# 邮件代理
适用于 **AI 代理** 和 **QA/E2E** 的临时邮箱:创建邮箱,提交地址到注册/登录表单,等待 OTP 或神奇链接,并自动清理。
工作空间代理添加了提供的线程摘要、草稿回复、提醒、持久操作历史和存储的入站消息的策略门控幂等回复。默认情况下,发送功能被禁用;日历写入仍然被禁用。
**路线图:** [docs/ROADMAP.md](./docs/ROADMAP.md)
**您自己的代理,无需我们的 API:** [docs/INTEGRATE.md](./docs/INTEGRATE.md) — 自主托管、MCP、REST。
**适用于 QA:** [docs/QA.md](./docs/QA.md) — 标签、subjectContains、回调、Playwright。
生产环境:[webmailagent.com](https://webmailagent.com) · API:[api.webmailagent.com](https://api.webmailagent.com) · 远程 MCP:`https://api.webmailagent.com/mcp`.
代理响应包括 `otp`、`primaryLink`、`primaryButton`、置信度元数据、原始 MIME 链接、附件、诊断提示、运行时间线和清理策略字段。
## 技术栈
- Cloudflare Workers + Hono
- Cloudflare Queues (+ DLQ)
- Durable Objects (SSE `/events`)
- Neon Postgres
- Resend Inbound
完整设置(包含密钥):**[SETUP.md](./SETUP.md)** · 检查:`npm run setup:check`
## 快速开始
### 托管 QA / 代理烟雾测试
```bash
export MAILAGENT_API_URL=https://api.webmailagent.com
export MAILAGENT_API_KEY=ma_...
npm run doctor:qa
npm run smoke:qa
```
QA 启动器:[examples/qa-pilot-starter](./examples/qa-pilot-starter) · Cypress:[examples/qa-pilot-cypress-starter](./examples/qa-pilot-cypress-starter) · 代理交接:[docs/AGENT-HANDOFF.md](./docs/AGENT-HANDOFF.md).
### 自主托管设置
#### 1. 依赖项
```bash
npm install
```
#### 2. Neon
在 [neon.tech](https://neon.tech) 上创建项目,复制连接字符串。
```bash
cp .env.example .env
# 填写 DATABASE_URL
npm run db:migrate
```
#### 3. Resend
1. API 密钥 → `RESEND_API_KEY`
2. 仪表盘 → **电子邮件 → 接收** — 复制域名 (`xxxx.resend.app`) → `INBOX_DOMAIN`
3. **网络钩子** → 事件 `email.received` → URL: `https://<worker>/webhooks/resend`
4. 签名密钥 → `RESEND_WEBHOOK_SECRET`
本地开发:`npm run dev` + 隧道(cloudflared / ngrok)到 wrangler 端口。
#### 4. Worker 密钥
```bash
npx wrangler secret put DATABASE_URL
npx wrangler secret put RESEND_API_KEY
npx wrangler secret put RESEND_WEBHOOK_SECRET
npx wrangler secret put API_KEY
npx wrangler secret put INBOX_DOMAIN
```
本地开发:创建 `.dev.vars`(相同键,见 `.env.example`)。
#### 5. 部署
```bash
npm run deploy
```
首次部署会创建队列 `mailagent-email` 和 `mailagent-email-dlq`.
## API
受保护的 `/v1` 端点需要以下头部:
```
Authorization: Bearer <API_KEY>
```
| 方法 | 路径 | 描述 |
|-------|------|----------|
| `GET` | `/v1` | 发现:端点、预设、MCP 工具 |
| `GET` | `/v1/agent` | 代理中心:工具、流程、文档、OAuth/MCP 元数据 |
| `GET` | `/v1/openapi.json` | OpenAPI 3.0(代理) |
| `POST` | `/v1/agent/verify` | 首选代理验证流程,带有 `agent.primaryAction` |
| `GET` | `/v1/agent/flows` | 注册/登录/重置/邀请流程模板 |
| `GET` | `/v1/agent/runs/:runId/timeline` | 代理可读运行时间线 |
| `POST` | `/v1/inboxes/open` | **一次性:** 创建 → 等待 → 提取 → 删除 |
| `POST` | `/v1/inboxes` | 创建邮箱(`ttlMinutes`、`service`、`expectFrom`、`notifyEmail`、清理策略) |
| `GET` | `/v1/inboxes/:id` | 状态 |
| `GET` | `/v1/inboxes/:id/messages` | 消息 |
| `GET` | `/v1/inboxes/:id/extract` | OTP、链接、`primaryButton`、置信度来自最新消息 |
| `GET` | `/v1/inboxes/:id/events` | **SSE** — 等待新消息 |
| `GET` | `/v1/inboxes/:id/wait?timeout=60` | 轮询回退(每 500ms) |
| `GET` | `/v1/inboxes/:id/diagnose` | 故障恢复提示和重试有效载荷 |
| `POST` | `/v1/inboxes/:id/simulate` | QA/开发模拟消息,无需 SMTP |
| `GET` | `/v1/inboxes/:id/search?q=` | 搜索消息 |
| `GET` | `/v1/inboxes/:id/callbacks` | `callbackUrl` 交付日志(QA) |
| `GET` | `/v1/inboxes/:id/notify-deliveries` | `notifyEmail` 中继日志(手动 QA) |
| `GET` | `/v1/inboxes/:id/messages/:messageId/raw` | 原始 MIME `.eml` 下载 |
| `GET` | `/v1/inboxes/:id/messages/:messageId/attachments` | 附件元数据/下载 |
| `GET/POST` | `/v1/domains` | 自定义域名 DNS 设置 |
| `POST` | `/v1/emails/check` | 电子邮件检查:语法、一次性、角色、MX(无 SMTP 探测) |
| `DELETE` | `/v1/inboxes/:id` | 删除 |
| `GET` | `/v1/stats` | 邮箱/消息计数器(24 小时) |
| `POST` | `/webhooks/resend` | Resend 网络钩子(无 API 密钥) |
| `GET` | `/health` | 数据库 ping |
### 示例
```bash
# 创建邮箱
curl -s -X POST "$MAILAGENT_API_URL/v1/inboxes" \
-H "Authorization: Bearer $MAILAGENT_API_KEY" \
-H "Content-Type: application/json" \
-d '{"ttlMinutes":15,"service":"auth0","deleteAfterSuccess":true}' | jq
# SSE(另一个终端)
curl -N "$MAILAGENT_API_URL/v1/inboxes/<id>/events" \
-H "Authorization: Bearer $MAILAGENT_API_KEY"
```
## 可靠性
- 网络钩子在 `MAIL_QUEUE.send` 后立即响应
- 幂等性:`messages.provider_id` = Resend `email_id`(唯一)
- 队列重试最多 5 次 → DLQ
- 每小时 cron:删除过期的邮箱
- OTP/链接在队列处理中提取,而不在网络钩子中
## 自定义域名(生产环境)
在 Resend 中:MX 在子域名 `inbox.yourbrand.com` 上,`INBOX_DOMAIN=inbox.yourbrand.com`.
## MCP for Cursor / Codex / 代理
官方协议 [Model Context Protocol](https://modelcontextprotocol.io);SDK:[`@modelcontextprotocol/sdk`](https://www.npmjs.com/package/@modelcontextprotocol/sdk)(stdio)。
### npm 包
已发布包(参见 [docs/PUBLISH.md](./docs/PUBLISH.md)):
```bash
npm install @mailagent/mcp # stdio MCP for Cursor
npm install @mailagent/agent # REST + 远程 MCP SDK
npm install @mailagent/qa # Playwright / Cypress QA
```
本地构建:
```bash
npm run build:mcp
npm run build:qa
npm run build:agent
```
远程 MCP(生产环境):`https://api.webmailagent.com/mcp` — OAuth/DCR:[docs/MCP-OAUTH.md](./docs/MCP-OAUTH.md). Codex 指南:[docs/CODEX.md](./docs/CODEX.md).
### 构建 MCP 服务器(从仓库)
添加到 `.env`(参见 `.env.example`):
```
MAILAGENT_API_URL=https://api.webmailagent.com
MAILAGENT_API_KEY=<与 Worker 相同的 API_KEY>
```
### 在 Cursor 中连接
项目已经有 [`.cursor/mcp.json`](.cursor/mcp.json):
```json
{
"mcpServers": {
"mailagent": {
"command": "node",
"args": ["mcp/dist/index.js"],
"envFile": ".env"
}
}
}
```
1. **Cursor 设置 → MCP** — 服务器 `mailagent` 应该为绿色
2. 点击工具列表中的 **刷新**
3. 在 Agent/Composer 中:”通过 mailagent 创建邮箱“ — 代理将调用工具
全局适用于所有项目:复制块到 `~/.cursor/mcp.json`(`mcp/dist/index.js` 的绝对路径)。
### 工具
| 工具 | 目的 |
|------|------------|
| `mailagent_issue_access` | 为一次自主代理运行颁发短期作用域密钥 |
| `mailagent_start_run` | 启动服务端运行状态并获取第一个自动驾驶计划 |
| `mailagent_report_run` | 报告进度/失败并获取下一个计划 |
| `mailagent_next_run` | 从保存的状态恢复运行并获取下一个计划 |
| `mailagent_plan_next` | 自动驾驶规划器:返回下一个工具、有效载荷和恢复步骤 |
| `mailagent_workspace_summarize` | 工作空间预览:总结提供的邮件/线程消息 |
| `mailagent_workspace_draft_reply` | 工作空间预览:仅草拟回复,永不发送 |
| `mailagent_workspace_suggest_reminders` | 工作空间预览:建议提醒/跟进 |
| `mailagent_workspace_create_reminder` / `list_reminders` / `complete_reminder` | 工作空间预览:持久化和管理跟进 |
| `mailagent_workspace_log_action` / `list_actions` | 工作空间预览:记录和检查代理操作历史 |
| `mailagent_workspace_get_policy` / `set_policy` | 读取或配置管理员拥有的自主权护栏 |
| `mailagent_workspace_model_status` | 检查 DeepSeek/Qwen 准备情况和备用优先级 |
| `mailagent_workspace_execute_reply` | 干燥运行或执行幂等策略门控回复 |
| `mailagent_suggest_preset` | 从示例身份验证电子邮件中建议 `service`、`expectFrom`、`subjectContains` 和 `flow` |
| `mailagent_verify_signup` | **首选:** 等待并返回 `agent.primaryAction` |
| `mailagent_create_inbox` | 创建邮箱(`service`、`notifyEmail`、清理选项) |
| `mailagent_wait_and_extract` | 创建/等待/提取/删除一次性流程 |
| `mailagent_wait_for_message` | 等待第一个消息(SSE,最大 120 秒) |
| `mailagent_extract_verification` | OTP、链接、置信度、`primaryButton` |
| `mailagent_extract_structured` | 预设:`2fa`、`magic_link`、`invite`、`invoice`、`receipt` |
| `mailagent_diagnose_inbox` | 超时/调试提示和重试有效载荷 |
| `mailagent_simulate_message` | 注入 QA 邮件,无需 SMTP |
| `mailagent_list_messages` | 所有消息 |
| `mailagent_search_messages` | 搜索消息 |
| `mailagent_get_raw_message` | 原始 MIME |
| `mailagent_list_attachments` / `mailagent_get_attachment` | 附件 |
| `mailagent_check_email` | 仅应用电子邮件验证测试 |
| `mailagent_send_message` / `mailagent_list_threads` | 外发/回复和对话视图 |
| `mailagent_get_run_session` / `mailagent_get_run_timeline` | 代理运行内存和时间线 |
| `mailagent_cleanup_inboxes` | 通过 `labelPrefix` 或 `runId` 清理 |
| `mailagent_get_inbox` | 邮箱状态 |
| `mailagent_delete_inbox` | 早期删除 |
完整当前列表:`GET /v1/agent` 返回 `mcpTools`(目前 38 个)。
代理技能:[`.cursor/skills/mailagent-mcp/SKILL.md`](.cursor/skills/mailagent-mcp/SKILL.md)
### CLI(终端 / CI)
在 `npm run build:mcp` 之后:
```bash
# 一步操作:邮箱 + 等待 OTP(service=dribbble)
MAILAGENT_API_URL=... MAILAGENT_API_KEY=... \
node mcp/dist/cli.js open --service dribbble --json
# 或分步操作
node mcp/dist/cli.js inbox create --service dribbble
node mcp/dist/cli.js wait <inboxId> --json
```
`service` 预设包括 `github`、`google`、`auth0`、`gitlab`、`bitbucket`、`stripe`、`vercel`、`supabase`、`clerk`、`discord`、`openai`、`resend`、`firebase` 等。可以通过 `GET /v1/agent` 发现当前列表。
对于自主浏览器/QA 运行,调用 `POST /v1/agent/runs/start` 或 MCP `mailagent_start_run`,执行 `plan.nextTool`,然后在每个步骤后调用 `mailagent_report_run`。如果代理失去上下文,`mailagent_next_run` 从保存的状态恢复。当没有活动邮箱流程时,运行规划检查提醒、操作历史和存储的自主策略:它可以选择草稿,执行守卫回复,或返回 `workspace_waiting` 而不重复工作。
工作空间自主指南:[docs/WORKSPACE-AUTONOMY.md](./docs/WORKSPACE-AUTONOMY.md).
工作空间模型路由使用配置的主要提供商,并在 DeepSeek 和 Qwen 之间自动备用。可以使用 `GET /v1/workspace/models` 或 MCP `mailagent_workspace_model_status` 检查准备情况;无限制的管理员可以运行 `POST /v1/workspace/models/probe`.
如果下一个操作不明确,调用 `POST /v1/agent/autopilot` 或 MCP `mailagent_plan_next`;它返回 `nextTool`、`nextPayload` 和恢复有效载荷。如果发件人或主题提示不明确,调用 `POST /v1/agent/preset-advice` 或 MCP `mailagent_suggest_preset`,并附上示例 `from` / `subject`.
### 一次性(代理 / CI)
```bash
curl -s -X POST "$MAILAGENT_API_URL/v1/inboxes/open" \
-H "Authorization: Bearer $MAILAGENT_API_KEY" \
-H "Content-Type: application/json" \
-d '{"service":"github","timeoutSeconds":90}' | jq
```
### MCP 调试
- 日志:命令面板 → **MCP:显示日志**
- 不要在 MCP 中使用 `console.log` — 否则 stderr 仅限,JSON-RPC 损坏
- 手动检查:`cd mcp && MAILAGENT_API_KEY=... MAILAGENT_API_URL=... node dist/index.js`
## 安全(允许列表)
创建邮箱时传递预期发件人 — 其他邮件 **不存储**:
```json
{ "expectFrom": "noreply@stripe.com" }
{ "expectFrom": ["noreply@auth0.com", "auth0.com"] }
{ "allowedSenders": "github.com" }
```
空 `allowedSenders` = 接受所有(仅限开发)。
## CI
- **部署:** `.github/workflows/deploy-worker.yml` — 机密 `CLOUDFLARE_API_TOKEN`、`CLOUDFLARE_ACCOUNT_ID`;部署后可选 `MAILAGENT_API_KEY` 用于烟雾测试
- **npm 发布:** `.github/workflows/publish-packages.yml` — 机密 `NPM_TOKEN`
- **生产环境门控:** `npm run test:prod:gate`;完整合约:`npm run test:prod`
详情:[docs/CI.md](./docs/CI.md) · [docs/PUBLISH.md](./docs/PUBLISH.md)
## 当前状态
- 代理原生 PBR 已实现:诊断恢复、置信度元数据、流程模板、运行时间线、清理策略、HTML 操作提取。
- QA 试点套件已准备就绪;下一个非代码步骤是候选人外联:[docs/PILOT-CANDIDATES.md](./docs/PILOT-CANDIDATES.md).
- 另一个代理/会话的无密钥交接:[docs/AGENT-HANDOFF.md](./docs/AGENT-HANDOFF.md) 或 `npm run print:agent-handoff`.
- Stripe 处于暂停状态,直到税务/账户设置准备就绪。