用户与 agent 怎样开始
两种接入版本共同建设
Plus One 同时提供两种正式产品路径:版本 A 向用户已有邮箱发送 Karpo 信息与任务请求;版本 B 让 personal agent 使用用户的 Karpo 邮箱,其中 B1 是标准 IMAP/SMTP,B2 是 OAuth HTTP API。 两者共享用户、会话、权限策略和操作记录,用户可以只用 A、只用 B,或从 A 升级到 B。B 不替代 A。本轮补充 A 的“一段提示词绑定已有邮箱”入口,独立于 B1 推进;B1 继续完成标准邮箱能力,B2 后续扩展到邮件之外的 Karpo 能力。
本节是两种版本的目标技术方案。已有 AWS 邮件传输与存储可复用;A 首版复用已验证邮箱和现有发信通道,新增外部邮箱绑定意图与验证流程;受限回信桥接是后续能力。B1 协议代码已开始开发,正式存储适配和部署尚未完成;B2 OAuth、正式 HTTP 接口和通用增量事件尚待实现。接口、scope 与数据实体名称是拟定契约,落地时与正式 API 和 schema 仓库对齐。
| 对比 | A 已有邮箱 | B1 标准 Karpo 邮箱 | B2 Karpo OAuth 连接 |
|---|---|---|---|
| 使用的邮箱 | 用户原有 Gmail、Outlook 等 | 用户拥有的 Karpo 邮箱 | 同一个 Karpo 邮箱与其他业务资源 |
| 用户入口 | 一段提示词启动现有邮箱绑定;复用已验证地址 | 在 agent 的邮件工具添加账号 | 复制接入提示词并确认 OAuth |
| agent 前提 | 已有该邮箱连接 | 支持通用 IMAP/SMTP 工具 | 支持 HTTP/CLI 或 OAuth 连接器 |
| 凭据 | 复用 agent 原有连接 | 每个 agent 独立、可撤销的应用密码 | 短期访问令牌与可撤销刷新凭据 |
| 首要能力 | 接收信息、任务请求、已有操作链接 | 查询邮件、附件、回复和发送、共享阅读状态 | 邮件读写,再以独立 scope 扩展订阅和其他业务 |
| 实施顺序 | 本轮补充绑定入口,然后发送并验证 agent 表现 | 独立完成真实邮箱端到端验收,不是 A 绑定的前置 | 按独立业务权限推进 |
“无感”指无需重复接入新邮件工具。已有且用途匹配的邮箱验证可以复用;首次使用仍须确认目标地址和通知偏好。Karpo 不读取用户整个 Gmail,也不为 A 获取 Gmail 邮件读写 OAuth 令牌;可选的提供商身份登录只验证必要身份声明。agent 尚未连接邮箱时,用户仍需在其平台连接;邮件只能提出任务请求,不能自行增加 agent 权限或保证自动唤醒。
A 的入口:一句话绑定现有邮箱
本轮新增的目标是把用户正在使用的邮箱关联到自己的 Karpo ID。它是 A 的身份接入步骤,不需要等待 B1 的 IMAP/SMTP,也不要求 B2 的长期 OAuth 委托先上线。 绑定后 Karpo 可以按已选偏好向该地址发信息;不会因此读取原邮箱、以它代发、创建 Karpo 邮箱、合并登录账号或自动订阅频道。
这里的 Karpo ID 指正式用户身份对应的稳定标识,不是 mailbox_id、邮件地址、显示名称或 agent 自报 ID。服务端通过现有登录解析真实用户,再确认目标身份归属;提示词中的 ID 只作展示和核对,不作授权依据。初版只绑定本人账号,团队代管和共享地址另行设计。
用户看到的提示词(产品将占位符替换为经过验证的官方入口;当前不是已上线链接):
把我现在使用的邮箱关联到我的 Karpo:【Karpo 生成的绑定链接】。帮我完成邮箱验证,成功后告诉我绑定的邮箱和 Karpo ID。需要我登录或确认时再叫我。
不要求安装 Karpo CLI 或 MCP。agent 复用已有邮箱工具及浏览器/HTTP 工具,读取官方说明、查收验证邮件并提交证明。只有固定聊天能力、无法访问邮箱或网页的平台不能保证自动完成;用户可以在同一个页面完成验证,不换一套绑定流程。
最少交互的用户流程
- 确定邮箱:agent 从已有工具的账户信息读取候选地址,不能从发件人显示名称、历史聊天或第三方邮件猜测。只有一个符合用户请求的邮箱时直接使用;存在 Gmail 和 bot 自带邮箱等多个候选时,只问一次要绑定哪个。不能默默把 bot 邮箱当作用户个人邮箱。
- 确认 Karpo 归属与意愿:官方页面复用 Karpo 登录,展示“此邮箱 → 此 Karpo ID”和用途,用户确认一次。如果用户已在 Karpo 页面选定这个确切地址并点击「确认并复制指令」,记录过同一操作的确认,就不再要求第二次确认。地址在 agent 中才确定或被改动时,原来的笼统授权不能替代对新地址的确认。
- 验证邮箱控制权:优先复用该 Karpo 用户的、符合用途与时效策略的已验证地址;否则向确切地址发送一次性验证邮件。agent 在当前任务中有界查询该邮箱,读取本次验证码/证明,再通过 HTTPS POST 提交。它是在执行用户主动发起的绑定任务,不依赖新邮件自动唤醒。
- 事务完成关联并返回结果:后端同时核对身份、确认记录、邮箱证明、期限及现有绑定,持久化关联后才返回
bound。agent 报告确切邮箱、Karpo ID 与绑定结果;“链接已打开”“验证信已投递”均不是成功。查询暂时收不到信时返回待处理状态,不不断重发,也不凭 SMTP Delivery 判定验证成功。
能做到“一段提示词启动”,但不能承诺任何账号都零确认。 已登录、确切邮箱已确认且验证可复用时可直接结束;首次绑定通常需要一次 Karpo 登录/确认和一次邮箱证明。如果两者在同一已登录页面已完成,agent 只需查询最终结果,不必再打开授权页。用户登录 session、邮箱密码和供应商 access token 不转交给 agent。
三条证明路径,共用一个绑定结果
| 路径 | 如何证明 | 用户需要做什么 | 边界 |
|---|---|---|---|
| 复用已验证邮箱(优先) | 正式身份服务中,该用户的同一确切地址已有有效验证记录 | 核对地址、目标与用途;已确认则直接完成 | 不能仅因为前端显示了 email 就信任;停用、归属变化或高风险时重新验证 |
| 验证邮件(通用) | 只发送到目标邮箱的高熵一次性证明,经官方页面/HTTP POST 提交 | agent 有读取权限时可完成;受平台限制则由用户在页面验证 | 请求创建响应和提示词不包含邮箱证明;扫描器 GET 不消费、不绑定;验证信丢失时保留 pending |
| 邮箱提供商身份登录(可选) | 官方 OAuth/OIDC 回调验证发行方、签名、audience、nonce、有效期及可信已验证邮箱声明 | 在提供商页面登录/确认,可与当前 Karpo 登录体验合并 | 只申请必要的身份信息,不申请整个 Gmail 邮箱读写权限;仅支持已实现且核实声明语义的提供商 |
OIDC 的稳定账户关联使用 iss + sub,不能用可变的 email 字符串替代主体标识;只有可信且校验通过的已验证邮箱声明才可作为本次邮箱证明。不同提供商、邮箱类型和企业租户的声明可信度需分别核查。OIDC 标准声明与稳定性
仅支持邮件工具、不能 POST 的 agent 可在后续采用验证回信:携带本次随机证明,发往不可猜测的专用回复地址。入站服务核对意图、地址、有效证明以及可信 SES 入站认证结果,不能仅凭 From 绑定。此为兼容扩展,不作为第一版上线前置。没有读取能力时,只能证明“能发邮件”,不足以证明控制了收件邮箱。
服务端契约与持久化状态
现有 apps/web/app/mail/connect 面向 B1 凭据交付,不能直接改成外部邮箱归属服务。新增“绑定现有邮箱”入口,保持两者文案、接口及权限独立。下面是待实施契约,正式 host 在部署前确定;不能把 api.karpomail.com 的旧实验记录器或 connect-test.karpomail.com 的模拟记录用作真实绑定后端。
| 拟定接口 | 身份与行为 |
|---|---|
POST /identity/v1/email-binding-intents |
Karpo 登录态创建,或 agent 创建未授权草稿。草稿不能发验证信、不能绑定;请求 ID 不能授权操作其他用户 |
POST /identity/v1/email-binding-intents/{id}/authorize |
用户在官方同源页面完成登录并确认确切地址、自己的目标 Karpo ID 及用途;CSRF 防护。服务端派生所有者,禁止提交任意 user_id |
POST /identity/v1/email-binding-intents/{id}/challenge |
仅所有者登录态可对已确认意图向锁定地址发证明;首次发送由确认操作自动入队,无需多点一次;重发有冷却、限流、幂等,邮件与状态使用 outbox |
POST /identity/v1/email-binding-intents/{id}/verify |
提交本次邮箱证明;验证并在一个事务内消费证明、建立关联、写审计/结果事件。重试返回同一结果 |
GET /identity/v1/email-binding-intents/{id} |
仅所有者登录态或短期、只读且只限本次意图的查询凭证读取脱敏状态/结果;知道 ID 或打开链接不足以读取用户信息 |
DELETE /identity/v1/email-bindings/{id} |
已认证所有者解除关联;后续通知发送前重新检查有效性,已提交给邮件供应商的邮件不可召回 |
agent 发起草稿时获得随机查询句柄/短期查询凭证及供用户使用的官方确认入口;用户在自己的浏览器登录,agent 轮询结果,不需要取得用户浏览器 cookie。查询凭证不授予邮箱读取、代发或新增绑定能力。意图完成用户授权后,原 agent 的短期查询凭证才可读取这次关联的完整地址、Karpo ID 与结果;授权前仅显示脱敏状态。
状态按 awaiting_user → awaiting_email_proof → bound 推进;拒绝、过期、撤销、冲突为独立终态,重发只替换当前未使用证明,不重置整项授权的最长有效期。验证通过的地址可跳过 awaiting_email_proof。SMTP 送达是独立的 delivery 状态,不是这里的状态迁移。拟定意图有效期 15 分钟、邮箱证明有效期 10 分钟且不超过意图期限;原子消费后失效,重复验证不创建第二条绑定。
逻辑上需要 EmailBindingIntent(所有者、目标、确切地址、确认版本、证明摘要、期限及幂等结果)和 ExternalMailboxBinding(用户 ID、原始/规范化地址、验证来源与时间、用途、状态)。正式存储复用 Karpo 身份域与 PostgreSQL;先检查已有表,再在 karpo-db-schema 扩展,Plus One 和 Worker 不另建用户主库。绑定成功本身不产生长期 agent token;B2 的 AgentConnection 单独申请。
首版约束:同一规范化地址最多存在一个有效的个人 Karpo 绑定,同一 Karpo 用户可绑定多个地址;同用户重试返回原记录,跨用户冲突不自动抢占、不泄露另一用户资料。改绑须现有主体解除或走正式恢复流程。邮箱域名统一处理,local-part、加号别名和点号不作跨提供商的猜测性合并;不能把绑定地址自动升级为 Karpo 登录/找回密码因子。
写入采用事务及唯一约束防并发重复;取消/撤销与验证竞争时以持久化状态判定。确认后改变目标、地址或用途必须废弃旧证明并重新确认。证明只存摘要,限制尝试次数;令牌、证明、完整授权头不得进入日志/遥测。验证信只发往已获用户确认的地址,按用户、地址及来源限流;不存在的账户和跨用户冲突对外使用不泄露身份的错误。生产、offline 和实验的证明、audience 与数据环境不可混用。
本轮实施与验收
Mock 演示已可用: 打开现有邮箱绑定演示。模拟 Leo / Alex、固定 example.test 邮箱、一次确认、模拟验证信、绑定状态和撤销均有可执行页面及 HTTP 接口。实现见 Mock 模块,独立 Worker/D1 只保存合成数据,不是正式用户主库。助手使用现有 HTTP 工具读取接入说明和提交模拟证明,不需安装专属 CLI/MCP。
本地测试覆盖用户与 agent 权限分离、验证前拒绝绑定、重复/并发提交、过期、取消、锁定、跨用户冲突和撤销。Mock 收件箱模拟邮件工具的作用,不能作为真实邮箱控制权证据,也不证明 Grok/Dots 已响应。正式身份及真实邮件验收仍按以下顺序完成:
- 先接正式 Karpo 登录与用户解析,完成确切地址的确认界面,以及可复用的验证记录检查;在同一个页面提供人类表单与 agent 可读说明,不要求专属安装工具。
- 实现意图、一次性证明、唯一关联、撤销与 outbox;使用现有 Mail RPC/SES 发验证信,读取能力继续由 agent 原有邮箱工具提供。正式 API/身份仓库和验证字段需核实;当前已实现独立 Mock 接口,正式身份与真实发信适配尚未接入。
- 在 offline 数据与身份环境验证 Gmail 和 bot 自带邮箱各一条路径;外部邮箱无需改 MX,也不领取
offline.karpomail.com的协议密码。先确认 agent 能实际检索验证邮件,再评估自动提交和文案效果。 - 以“收到一个提示词 → 用户必要的确认 → 地址已验证 → 后端
bound→ agent 读回结果”为验收;另外验证错误账号、错误邮箱、被转发的旧证明、并发重放、过期、取消、跨用户冲突、扫描器 GET、收不到信以及无读信工具时的明确回退。绑定不能解锁 B1/B2 权限或订阅未选择的频道。
Grok 实验已证明收件服务器接收 8 封邮件,但截至 2026-10-20 的已收集记录未出现测试链接访问或确认。用户主动询问后,bot 自述只看到此前发件,底层查询结果未显示。这不能证明它有完整收件检索或自动唤醒能力;本方案因此以用户提示词主动启动任务,并把“能实际检索本次验证信”设为前置验收。现有模拟确认页不计入正式绑定成功证据。
Karpo 内直接使用
已登录用户打开邮箱,由正式 API 根据认证身份调用 EnsureMailbox,显示稳定地址并复用已有消息、线程和草稿能力。未连接任何 agent,也能拥有并使用邮箱。用户改名、更换 agent 或供应商不自动改变地址;已有邮箱只是可更换的外部入口,不替代 Karpo 用户身份。
正式 API 仓库及当前邮件 HTTP 路由尚未取得。接入时先找到已有登录和 API 调用链,补缺失环节,不另建 Plus One 登录或用户主库。尚处于 S3 待领取状态的地址可以继续收信,但开放访问前必须完成归属核验。
版本 A 直接发送到已有邮箱
A 的发送阶段只需要已验证的收件地址、信息清楚的邮件与现有发信通道;地址的首次关联使用上面的绑定流程。邮件可以提供已有的订阅或活动页面链接,agent 使用自己的浏览器、日历等工具处理。无需先建设新的回信路由、交互数据库或 OAuth 授权层;也无需把所有二十种实验变成后端功能。
以下回信契约适用于未来需要“Karpo 根据邮件回复自动修改业务状态”时,不作为 A 首版的前置。
以用户原有的 liuyitao811@gmail.com 为例:
- 用户选择已有的已验证邮箱并开启通知类别、频率和允许的交互;首次绑定或更换地址需验证控制权。
- Karpo 在相关事件发生时发送普通邮件,包含上下文、明确请求、有效期和回复方式。例如邀请订阅某个频道、请求回复可用时间,或请 agent 在已有权限内发送一封邮件。
- personal agent 通过自己已有的 Gmail 等邮件工具发现并处理。能自动执行的范围由用户在该 agent 平台的授权决定;需要确认时由 agent 请求用户确认。
- Karpo 收到回复或已确认的操作后,关联原会话,记录结果并发送必要反馈。用户也可以手工完成完全相同的交互。
邮件内容与回信契约:
- 邮件同时提供纯文本和 HTML,包含稳定请求 ID、原会话引用、具体动作与参数、期限;动作描述由受控模板生成。不要将转发来的第三方正文当作 Karpo 指令。
- 使用服务端生成、不可猜测的 Reply-To 路由,绑定用户、外部邮箱、会话、可执行动作及期限;数据库只保存路由令牌摘要。路由不携带邮箱 API 权限,泄露后可单独撤销。
- 订阅等状态修改由一次性请求标识约束,限定具体频道和选项;普通会话路由可以在有效期内接收多封不同回复,逐封去重,不能把整个会话误做成只能回复一次。
- 回信校验绑定地址、可信入站链路提供的发件认证结果、有效路由和当前权限。不能只看 From、Message-ID 或邮件自带的 Authentication-Results;认证失败或关联不明时不执行,转入待确认状态。
- 邮件中的链接 GET 仅展示预览;邮箱扫描器访问不能触发订阅、发信或变更。超出既有授权的操作在 Karpo 登录页面展示具体内容,由用户确认。退订立即阻止后续尚未提交的通知。
- 普通回复默认来自原有邮箱。若用户明确启用 Karpo 代发,桥接仅能回复指定会话的允许参与者;新增收件人、附件权限或新的发信意图须单独验证,不接受正文任意指定 From、用户 ID 或目标邮箱。
- “请 agent 向第三方发邮件”是任务请求;有无发出应由可核实回执或实际结果确认。agent 发回“已完成”只记为报告结果,不直接标记第三方已收到。
- 记录来源、父操作、稳定投递 ID、转送次数并限制自动回复链;自身通知和自动回复不能再次生成同一任务。多人或多个 agent 共用一个 Gmail 时,只能归因到该邮箱,不能声称识别了具体 agent。
A 的后续回信交互阶段支持订阅确认和回复 Karpo 会话。把发往用户 Karpo 邮箱的第三方来信转送到已有邮箱,并以 Karpo 地址回复原发件人,是 A 的后续桥接能力:只向绑定地址发送允许披露的内容,保留邮件核心中的原消息与会话映射,不另建 Gmail 历史副本库。网络内的内部收件人仍依赖下文的内部投递实现。
B1 标准邮件工具接入
当前先在 offline.karpomail.com 验证 B1。正式用户邮箱仍使用 karpomail.com;这次不会迁移、重命名或改动正式地址。Alex 的测试地址需在 offline 环境核对归属后开通,以下客户端配置尚不可登录:
| 配置 | 本轮测试目标 |
|---|---|
| 用户名 | alex@offline.karpomail.com |
| 收信 | offline.karpomail.com:993,TLS |
| 发信 | offline.karpomail.com:587,必须 STARTTLS |
| 凭据 | 领取一次性链接后激活并保存在 agent 环境,不需要手动复制 |
两个协议暂共用一个测试主机名,减少用户参数和证书配置。该主机的客户端入口需在 TCP 服务就绪后配置;现有 MX 仍负责公网邮件接收,不是 IMAP/SMTP 登录地址。
2026-10-19 只读核查已确认:offline MX 指向 AWS SES 美东;独立 offline 收信规则已启用,SES 发信身份、DKIM 和 bounce.offline.karpomail.com MAIL FROM 验证成功。Machine Cloud 页面已确认现有邮件服务位于 US / offline_base,实例健康,当前只有 TCP 50051 RPC 端口,由 Forge 构建;EKS 是生产部署目标,生产 SSO 不是这轮 offline 测试的前置。
测试发布必须显式设置 MAIL_DOMAIN=offline.karpomail.com,核对 offline 数据库、入站队列、回执队列和发送配置集,并把域名传给协议网关。网关在登录和后续读写时拒绝其他邮箱域,未配置域名则拒绝访问。桶可以沿用现有共享 S3,但不能因此混用生产数据库或消费生产队列。迁移先应用到已核实的 offline 数据库;当前尚未执行线上迁移或协议部署。
B1 的产品入口是「连接我的 agent」,放在 Plus One,复用 Karpo 现有 Clerk 登录和内部用户解析。已登录用户点击「复制接入指令」,即授权领取链接的助手使用自己的邮箱;把指令交给 agent 后,不再打开第二个授权页,不输入或复制应用密码。
用户复制的短提示词:
帮我连接这个 Karpo 邮箱:【Karpo 自动生成的一次性连接链接】。直接完成连接,不需要再让我确认或填写密码。连好后告诉我收信和发信是否可用。
生成链接必须是邮箱主人主动触发的、经过登录校验的 POST;后端从真实 Karpo 身份确定邮箱与权限,不接受调用者指定其他用户 ID。链接五分钟有效,只能被一个客户端领取。链接本身是短期权限凭证,可以包含在用户交给 agent 的接入指令里,应只交给目标助手;长期邮箱密码、登录 session token 和客户端恢复码不进入提示词或日志。
agent 的连接工具在自己的运行环境生成高熵邮箱凭据及私有恢复码,先写入系统安全存储,再把链接令牌、凭据摘要和恢复码经 HTTPS POST 交给服务端。服务端在同一事务中消费链接并激活该邮箱的凭据,返回不含密码的标准协议参数。网页与服务器从未持有邮箱密码。链接放在 URL fragment,不发送到网页服务或 Referrer;打开网页、邮件扫描器 GET 都不会消耗它。
领取成功后,原链接不能再激活其他客户端;仅原客户端凭自己安全保存的恢复码,可在过期前重试领取同一结果,解决响应丢失问题。已领取链接不代表任何人都可以凭它恢复凭据。过期、撤销、邮箱停用或归属变化均拒绝领取。每个连接独立限于一个邮箱,凭据九十天有效,可独立撤销。
当前客户端支持 macOS 系统钥匙串和 Linux Secret Service;没有安全存储时停止,不降级为明文配置。工具从 stdin 读取一次性链接,不把令牌放进命令参数或 shell 历史。Windows 和第三方邮件工具的安全导入需分别适配。这是 B1 的一次性凭据交付,不是 B2 的 OAuth access-token 服务。
体验验收:用户只复制一次指令;工具完成领取、登录、只读 INBOX 检查和 SMTP 认证。配置检查不发送邮件;真实收发、回复和附件验证由明确的测试任务触发。界面区分「指令已复制」「连接已领取」与「收发验证通过」,不把收到参数视为连接成功。只有聊天或固定 Gmail 连接器的平台仍走 A,不能承诺任意 personal agent 都能靠一段文字获得新工具能力。
实现位置:Plus One apps/web/app/mail/connect 提供指令生成页及固定上游代理;Mail RPC cmd/mail-connect-server 生成、领取和撤销一次性链接,cmd/karpo-mail 保管凭据并通过标准协议查信、读取和发送。cmd/mail-standard-server 是单独部署的 offline IMAP/SMTP 入口,复用 canonical DB/S3/SES。它们尚未在 offline 公网启用。现有 api.karpomail.com 实验 Worker 不得接收这些真实 token。
B1 继续以现有 Mail RPC、PostgreSQL 与 S3 为邮箱核心,公网收发继续使用 SES。协议服务解释标准客户端命令,通过适配器读取同一份邮件并更新同一份状态;不单独安装一套与 App 数据分离的邮箱库,也不把共享 AWS SMTP 凭据交给用户。
实施顺序:
- 核对邮箱归属,建立独立应用密码的生成、摘要存储、限权和撤销。当前 Alex 的 S3 待领取副本不能直接作为所有权证明;不能为了开通协议而伪造用户 ID。
- 为每个文件夹持久化 UIDVALIDITY、递增 UID 与邮件映射,保证重启、并发、文件夹变化后不误认消息。现有 64 位邮件 ID 不能直接截断为 IMAP UID。
- 接入邮件列表、正文、MIME 附件、搜索及状态同步。明确 App 的 user-read 与 agent-read 语义;元数据和 BODY.PEEK 不标记已读。原文读取不能绕过恶意附件限制。
- SMTP 强制 TLS 与认证,限制信封和邮件头发件人;通过既有邮件核心处理配额、抑制、幂等及未知投递结果,保留原始 MIME 与已发送副本。客户端追加 Sent 副本不得制造重复邮件。
- 补多客户端同步、连接限流、证书续期与 AWS TCP 入口,再用真实 agent 验证。普通 HTTP Worker 路由不等于 IMAP/SMTP 入口。
当前 Mail RPC PR #24 是协议边界的草稿:本地 TLS/STARTTLS 和权限测试已通过,但尚未接入生产存储或开启监听。固定文件夹和基础读写适配不等于完整 IMAP 兼容性;IDLE、文件夹变动、APPEND 等必须逐项验证后再发布支持范围。
B1 上线验收:Alex 能通过标准工具登录、读到真实来信和附件、回复到外部邮箱;App 能看到已发送与约定的阅读状态;重连 UID 保持稳定;另一邮箱不可访问;撤销后既有连接不能继续读写。未取得这些结果前,不向用户宣布账号已可用。
B2 一段提示词与 OAuth 连接
用户流程:
- 用户在 Karpo 选定自己拥有的邮箱,点击「连接我的 agent」,选择初始权限,并复制 Karpo 生成的接入提示词。
- agent 读取官方接入说明,使用已发布的 CLI 或兼容连接器启动 OAuth,向用户返回授权页面或二维码。
- 用户在 Karpo 登录页确认 agent 名称、邮箱、请求权限及限制。凭据经 OAuth 直接交付给 agent 的工具运行环境;完成后 agent 查询授权信息并报告可用能力。
拟定的提示词形态如下;上线时由产品填入经过验证的官方入口和已发布版本,当前不是可直接执行的安装命令:
请连接我的 Karpo。按 Karpo 官方接入说明使用已发布的连接工具,申请读取我的邮箱及回复已有会话的权限。启动 OAuth 并把授权页面交给我确认。不要让我在聊天中粘贴访问令牌,也不要申请主动联系新收件人的权限。授权后核对邮箱及权限,列出最近的邮件;发送任何内容须遵循我授予的范围。
提示词是接入引导,不是凭据或授权凭证。公开 client_id、文档位置和拟申请 scope 可以包含在引导中;access token、refresh token 和 device_code 不进入提示词、对话记录或日志。只会聊天、不能使用外部工具或连接器的 agent,不能通过一段文字获得 API 能力。
OAuth 实现:
- 有浏览器回调能力的客户端采用 Authorization Code + PKCE;无合适回调的远程 CLI 可采用设备授权,遵循轮询间隔、过期、拒绝和 slow_down 语义。不能给公共 CLI 内置客户端秘密。RFC 8628 · OAuth 安全实践
- 复用正式 Karpo 登录认证用户;Karpo 的 agent 委托另有独立 audience、scope 和 connection。不能把用户登录 token 当成任意 agent 的长期通行证,也不能假定现有身份提供商已支持设备授权。
- 每个连接绑定内部用户、邮箱、客户端、允许资源及额度。短期 access token、轮换 refresh token、刷新重放检测和单连接撤销;凭据存运行环境的秘密存储,禁止进入模型上下文、仓库或遥测。
- 每次请求和排队操作执行前检查当前连接及权限;只校验尚未过期的 JWT 不足以实现及时撤销。撤销操作提交后,新访问和未提交外部发送必须拒绝;已经交给 SES 的邮件不能召回,记录为在途结果。
- 公开 API 从认证与委托派生 user_id、mailbox_id 和 actor,不接受客户端用 user_id 或 From 选择他人身份。消息、线程、附件及分页游标逐次检查资源归属。要求立即撤销的附件访问走受鉴权的下载入口;若签发独立 S3 下载链接,必须明确其到期前仍可能可用,不能承诺链接即时失效。
| 初始拟定权限 | 允许的操作 | 服务端限制 |
|---|---|---|
mailbox.read |
列表、正文、搜索、附件及邮件变化 | 只限获授权邮箱,附件链接短期有效 |
conversation.reply |
回复已有会话 | 必须能访问父消息,限定既有参与者;不能靠修改收件人变成新外发 |
mailbox.send |
主动发新邮件 | 校验收件人范围、额度和幂等键;发件地址由服务端确定 |
subscription.manage |
管理获授权的频道订阅 | 受资源范围和成员规则约束;不能通过订阅读取未获准内容 |
默认申请最小权限,新增能力另行增量授权。后续可加入活动、任务、日程或其他 Karpo 资源的独立 scope 与 API;复用同一连接体验和审计,但各业务保留自己的数据与授权边界。邮箱访问不会自动授予全部 Karpo 账号权限。
B2 正式接口与共用组件
正式 HTTP 路由部署在 Karpo 已有 API 服务中。Plus One 负责接入说明、CLI/skill、适配器和实验,不承担第二套用户和消息主库。
| 拟定接口 | 职责 | 复用与缺口 |
|---|---|---|
GET /mail/v1/me |
当前邮箱、连接及权限 | 封装 GetMailbox 与委托信息 |
GET /mail/v1/messages |
分页列出或筛选邮件 | 封装现有列表能力;查询条件以实际 RPC 为准 |
GET /mail/v1/messages/{id} |
正文与附件信息 | 复用 GetMessage,检查邮箱归属 |
POST /mail/v1/messages |
创建并发送邮件 | 复用 SendMessage,要求幂等键 |
POST /mail/v1/messages/{id}/reply |
回复父消息 | 封装现有回复能力并强制收件范围 |
GET /mail/v1/changes?cursor=… |
获取新增及状态变化 | 新增持久化增量接口 |
/connections、/subscriptions |
连接撤销及订阅管理 | 归正式 API 和各业务服务,具体路径在实施时确定 |
底层消息与发送状态仍由 Mail RPC 管理。外部绑定、agent 委托、交互请求和投递事件只保存各自必要的关联与状态:
| 逻辑实体 | 核心内容 | 所属边界 |
|---|---|---|
| EmailBindingIntent / ExternalMailboxBinding | 绑定意图、用户确认、证明摘要、唯一关联、验证来源、通知用途、撤销状态;详见 A 绑定契约 | Karpo 身份及通知接入 |
| AgentConnection | 用户、客户端、资源范围、scope、刷新凭据族、撤销状态 | Karpo 授权服务 |
| InteractionRequest | 会话、限定动作、路由摘要、期限、处理结果、父操作 | 通讯业务及邮件桥接 |
| ChangeEvent / DeliveryAttempt | 单调序列、事件 ID、资源 ID、消费者、重试与回执 | 对应业务的事务 outbox 与分发 |
以上是逻辑模型,不预设新表与已有表重复。先查正式 schema;所需 DDL 按仓库归属进入 karpo-db-schema。审计记录真实 actor 类型(用户、已授权连接或外部邮箱),不能把 A 的回信伪装成可识别的 agent OAuth 调用。
邮件入库或业务状态变更时,在同一数据库事务保存待分发事件。分发至少一次,消费方按事件 ID 去重;增量游标绑定用户、资源与过滤条件,按持久化提交顺序推进,不只依赖时间戳。游标过期显式要求重新同步,不能静默漏信。
A 的消费者生成邮件通知;B 的消费者提供游标轮询、长轮询或签名 webhook。webhook 仅携带事件和资源 ID,正文由 agent 持自己令牌拉取;重试有界并有死信及对账,回调地址验证防止访问内网。现有 WaitForMessage 不替代这个增量接口。发送同一幂等键而内容不同必须拒绝;外部发送结果未知时对账,不直接重发。
两条路径同时开启时,按用户、原事件和动作建立共同的操作状态与幂等约束。一次性的订阅确认无论从邮件还是 API 完成都只能生效一次;完成后另一入口显示已处理。普通不同内容的会话回复不做模糊去重。用户可把 B 设为主要处理入口,让 A 只发摘要,避免两个 agent 重复执行同一任务。
正式入口切换与协议兼容
api.karpomail.com 当前仍是实验 Worker。其 hit 会记录测试请求 Authorization 的前 80 个字符,因此真实 OAuth 凭据不得发往当前实验路径。上线 B2 前,把实验记录器迁至独立实验域名并隔离数据,停止正式入口的敏感头记录,完成鉴权、路由和回滚验证;正式域名归属在发布前固定,不把现有地址当成已可用 API。
标准 IMAP/SMTP 是 B1 的工作,独立于 A 的外部地址绑定、直接发信与 B2 的 OAuth 建设。现有 AWS SES 与 Mail RPC 未提供每邮箱 IMAP/SMTP 登录。不得将 SES 接收 MX 当作 IMAP 地址或发放共享供应商 SMTP 凭据;未来协议适配必须共享同一邮箱核心和授权策略。
两种版本的验收
| 范围 | 必须取得的结果 |
|---|---|
| A 首次绑定 | 一段提示词完成正确账号与确切地址的关联;无长期令牌交付;幂等、跨用户隔离、过期/撤销和扫描器 GET 验证通过 |
| A 首版 | 已验证邮箱收到 Karpo 信息与已有操作链接;记录 agent 是否发现、理解、执行或要求用户确认,不以回信业务处理作为前置 |
| A 订阅与撤销 | 一次订阅确认只生效一次;伪造、过期、已撤销、改目标与扫描器 GET 均不能触发状态修改;退出后未发通知被停止 |
| A 回信桥接 | 用户启用后能以自己的 Karpo 地址回复原会话;不能改成他人的身份或任意收件人,不能形成转发循环 |
| B2 首次连接 | 从接入提示词到授权完成;agent 能读取真实来信、以获授权邮箱回复;长期凭据不出现在聊天中 |
| B2 隔离与撤销 | 无法读取其他用户邮件/附件;仅回复权限不能主动外发;撤销后新读取和未提交发送失败,已提交发送状态可追踪 |
| 事件与恢复 | 断线重连、重复事件、多副本并发、游标过期及发送结果未知都不丢记录或盲目重发 |
| 两路协作 | 同一请求通过邮件和 API 重复到达只执行一次;换 agent 或切换入口不改变邮箱归属和历史 |
| 超出邮件的能力 | 在订阅能力上线时,以独立 scope 完成一次订阅/取消;只有邮箱权限的连接被拒绝,证明扩展能力仍受独立授权 |
真实 agent 验证分别记录:邮件送达、agent 发现、请求用户确认、工具执行、Karpo 状态变化及结果回传。区分自动发现与手工触发;没有外部回复不等同于 agent 没有私下提示。现有 T01–T20 是能力实验,本节验收覆盖产品可靠性和权限,二者分别报告。
迁移与实施顺序
| 顺序 | 工作 | 完成标准 |
|---|---|---|
| P0 | 查明生产运行版本、配置、正式 API 和用户邮箱数量;核对 DNS、SES/S3/SQS 实际链路 | 掌握有效生产入口和健康证据,而非仅 CI 绿色;核对 staging 生命周期偏差 |
| P0 | 保护地址并修复主域收信路由 | 查询两侧地址冲突并保留 iris/alex;用户已豁免历史导入;不按姓名自动归属用户;主域 MX 已切回 AWS,无账号 S3 收存已验证;后续核对 App 归属并处理旧入口在途邮件 |
| P1 | 接正式身份与邮箱 API;核对地址归属,隔离实验入口 | 用户无需供应商配置可使用自己的邮箱;跨用户访问拒绝;真实令牌不进入实验记录器 |
| P1 | 在 mail-rpc 增加内部投递及可恢复事件分发 | 内外混合、重试、部分失败、未知用户、屏蔽和发送额度均有回归;DDL 归 schema 仓库 |
| A 绑定入口(本轮) | 官方页面复用 Karpo 身份,绑定意图、邮箱证明、唯一关联及状态查询 | 用户一段提示词启动;完成必要的确认后拿到真实 bound 结果;Karpo 未获得原邮箱读写权限 |
| A 信息投递 | 向已绑定验证邮箱发送 Karpo 场景邮件与操作链接 | 验证真实收件可见性和 agent 表现;自动唤醒、回信桥接不作为首次绑定前置 |
| B1 独立推进 | 应用密码、IMAP/SMTP 适配、稳定 UID、共享状态及 AWS TCP 部署 | 完成真实收信、附件、回复、App 同步、隔离与撤销验收;不能以假存储测试替代上线 |
| B2 后续 | agent OAuth、连接管理、邮件 HTTP API、接入提示词与 CLI/兼容连接器 | 完成本节 B2 连接、隔离与撤销验收;与 A/B1 共享邮箱核心和操作记录 |
| P2 | 扩展频道、订阅 API 和其他 Karpo 业务 scope;按需增加标准协议 | 验证超出邮件的独立授权、成员权限、退出和摘要预算;用户不拿基础设施密钥 |
| 退出 | 移除 Resend 主域接收、撤销不再使用的 key/webhook、归档 Worker/D1 | 用户已豁免历史导入;在途新邮件处理完、监控与回滚验证完成后执行 |