shipmail-to/agent-inbox-starter

GitHub: shipmail-to/agent-inbox-starter

基于 Bun 和 TypeScript 的 Shipmail AI 邮件收件箱分类代理入门套件,通过多层安全控制让 Claude 安全地对入站邮件进行分拣并生成回复草稿。

Stars: 0 | Forks: 0

# Shipmail AI agent inbox 入门套件 一个独立的 Bun 和 TypeScript starter,用于通过 Claude 对 Shipmail 收件箱进行分类。它会验证 Shipmail webhooks,拦截未经批准的发件人,移除常见的 prompt injection 内容,对邮件进行分类,并创建防过期的回复草稿。默认情况下不开启发送功能。 ## 入站消息的处理流程 1. Shipmail 发送一个已签名的 `message.received` webhook。 2. 在验证签名之前,服务器会拒绝大于 1 MB 的请求体。这同时适用于声明的 `Content-Length` 值和流式传输的请求体。 3. 服务器验证签名并校验当前的 webhook 合约。 4. 在获取收件箱正文之前,会先检查可见的 `From` 地址。 5. Webhook 的 `email_id` 用于选择会话中对应的 provider 消息。如果缺失或未找到,接下来会尝试追踪到的消息 ID,最后尝试发件人的最新消息。 6. 当需要发件人身份验证时,消息必须具有 DMARC `pass` 验证结果。未通过验证的邮件将被升级处理,不会调用 Claude 或创建草稿。 7. 消息将被转换为纯文本。控制字符、类似指令的行以及未经批准的 URL 将被移除。 8. Claude 将消息分类为 `needs_reply`、`ignore` 或 `escalate`。 9. 常规回复会通过 `createInboxReplyDraft` 连同当前的 `reply_version` 一起保存。 10. 仅当 `AUTO_SEND=true` 时才会发送草稿。草稿的创建和发送使用从 webhook 事件 ID 派生的相互独立的稳定幂等键。 被忽略的会话将被标记为 `no_reply_expected`。被升级处理的会话将保留在回复队列中,等待人工审核。 ## 五分钟快速开始 前提条件:[Bun](https://bun.sh)、一个 [Shipmail 账户](https://shipmail.to) 以及一个 Anthropic API key。 1. 在 Shipmail 中,为 agent 创建一个 mailbox。 2. 创建一个具有权限范围限制的 API key。初始权限应包含收件箱读取和草稿写入权限。只有在计划启用 `AUTO_SEND` 时才添加发送权限。 3. 复制并填写环境变量文件: cp .env.example .env.local 4. 安装并运行服务器: bun install bun --env-file .env.local run dev 5. 使用以下任一隧道暴露本地服务器: cloudflared tunnel --url http://localhost:3000 ngrok http 3000 6. 为 `message.received` 创建一个 Shipmail webhook,地址指向 `https://your-tunnel.example/webhook`。将 webhook 的签名密钥放入 `SHIPMAIL_WEBHOOK_SECRET` 中。 健康检查 endpoint 为 `GET /health`。决策日志不会包含消息正文。 ## 配置 | 变量 | 用途 | | --- | --- | | `SHIPMAIL_API_KEY` | 具有权限范围限制的 Shipmail API key | | `SHIPMAIL_MAILBOX_ID` | 此进程接受的唯一 mailbox | | `SHIPMAIL_WEBHOOK_SECRET` | 创建 webhook 时返回的签名密钥 | | `ANTHROPIC_API_KEY` | Anthropic API key | | `PORT` | 本地 HTTP 端口,默认为 `3000` | | `SHIPMAIL_ALLOWED_SENDERS` | 必需的逗号分隔地址,或类似 `*@example.com` 的条目 | | `SHIPMAIL_ALLOWED_URL_HOSTS` | 可选的确切 host,或类似 `*.example.com` 的条目 | | `AUTO_SEND` | 为 `true` 时发送生成的草稿。默认为 `false` | | `REQUIRE_AUTHENTICATED_SENDER` | 在调用 Claude 之前要求 DMARC `pass`。默认为 `AUTO_SEND` 的值,因此当开启自动发送时,该选项默认开启 | 模型在 `src/agent.ts` 中被固定为 `claude-sonnet-5`。 ## 沙盒测试 Shipmail 沙盒入站注入功能可以测试真实的 mailbox 和 webhook 路径,而无需通过 SMTP 发送邮件: ``` bun --env-file .env.local run sandbox:e2e ``` 该脚本调用 `mailboxes.injectSandboxInbound`。其默认发件人是 `sandbox-sender@example.com`,因此需将该确切地址添加到 `SHIPMAIL_ALLOWED_SENDERS` 中以便进行测试。如有需要,可使用 `SANDBOX_FROM` 覆盖它。此脚本不属于 `bun test` 的一部分,并且需要真实的 Shipmail API key。 自动化流水线测试使用了模拟的 Shipmail 和 Anthropic 客户端。它不会发起任何网络调用: ``` bun test ``` ## 安全模型 电子邮件是受攻击者控制的输入。在此 starter 中,在模型能够影响任何操作之前,会应用多层独立的安全控制: - 在验证签名之前强制执行 1 MB 的 webhook body 限制 - 可见 `From` 地址的 allowlisting,支持可选的显式 `*@domain` 条目 - 当 `REQUIRE_AUTHENTICATED_SENDER=true` 时,在创建模型或草稿之前强制执行 DMARC 验证 - 对 `message.received` 进行签名验证和严格的 Zod 校验 - Mailbox ID 绑定 - 移除 HTML、脚本、注释、控制字符以及 Unicode 双向控制字符 - 在输入到模型之前,替换常见的 prompt injection 和角色操纵语句 - 公共 HTTPS URL 检查,拒绝包含凭证、localhost、私有地址、link-local、保留地址以及非常规数字 IP 格式的请求 - URL host allowlisting,所有其他 URL 将被脱敏 - 系统策略,以及 JSON 和 XML 样式的非可信数据分隔符 - 对模型允许的三种决策进行 Zod 校验 - 对生成的草稿进行二次安全检查 - 默认采取仅生成草稿的行为 - 进行 Shipmail `reply_version` 检查,并为草稿创建和发送使用基于事件的幂等键 Shipmail 会为每个收件箱消息返回 SPF、DKIM 和 DMARC 验证结果。当开启发件人身份验证强制检查时,此 starter 要求必须通过 DMARC。DMARC 将可见的 `From` 域名与对齐的 SPF 或 DKIM 结果绑定在一起。仅靠 SPF 是不够的,因为它检查的是 envelope sender,这可能与可见的 `From` 地址不同。 如果身份验证结果缺失、格式错误、为空,或者 DMARC 的验证结果不是 `pass`,该消息将保留在回复队列中等待人工审核。验证结果和原因将被记录。不会调用 Claude,也不会创建草稿。在 `AUTO_SEND` 模式下强制验证默认开启,在仅草稿模式下默认关闭。显式设置 `REQUIRE_AUTHENTICATED_SENDER` 可覆盖该默认值。 Allowlisting 虽然降低了风险,但在关闭身份验证强制检查时,并不能使发件人变得完全可信。模型的防御措施并不能防范未来所有的 prompt injection 技术。请针对您的使用场景审查策略、发件人列表、模型输出和操作日志。敏感、安全、法律、账户访问和财务相关的消息均被设计为需升级处理。 ## 部署到 Railway 从此仓库创建一个服务,添加 `.env.example` 中的环境变量,并使用: ``` bun install --ignore-scripts bun run start ``` Railway 会提供 `PORT`,starter 会读取该变量。将健康检查路径设置为 `/health`,然后创建 Shipmail webhook,地址指向 `https://your-service.example/webhook`。 ## 部署到 Vercel `api/webhook.ts` 适配器将相同的 Web Request handler 作为 Vercel Function 导出。导入该仓库,添加所有必需的环境变量并部署。在以下地址创建 Shipmail webhook: ``` https://your-project.vercel.app/api/webhook ``` Vercel 路由不会启动 `Bun.serve`。本地和 Railway 的入口点仍然使用 `src/index.ts`。 ## 示例 - `examples/vercel-ai-sdk`:通过 `ai` 包和 `@ai-sdk/anthropic` 进行最小化分类 - `examples/langgraph`:一个轻量级的 LangGraph 分类节点 - `examples/mcp-client`:托管的 HTTP 和本地 stdio MCP 配置,以及一个工具列表脚本 每个示例都有自己的 `package.json`,因此根目录的测试不会安装示例的依赖项。 ## Shipmail 链接 - [文档](https://shipmail.to/docs) - [面向 AI agents 的电子邮件指南](https://shipmail.to/docs/guides/email-for-ai-agents) - [TypeScript SDK](https://shipmail.to/docs/sdks/typescript) - [MCP 指南](https://shipmail.to/docs/mcp) - 托管的 MCP endpoint:`https://shipmail.to/api/mcp` ## 许可证 MIT。详见 `LICENSE`。
标签:Bun, TypeScript, Webhook, 力导向图, 启动模板, 安全插件, 自动化攻击, 邮件处理