# 多注册流程邮件分层设计 本文专门解决“邮件轮询虽然看起来像公共能力,但实际 OpenAI 规则已经写进 provider 脚本和后台轮询里”这个问题。 ## 1. 先说结论 邮件相关能力必须拆成两层,不能再只写一句“mail polling 通用化”: 1. `mail provider driver` 2. `flow mail rules` 前者负责“怎么从 Gmail / 163 / 2925 / Inbucket / API 邮箱里拿到邮件”,后者负责“哪封邮件算当前 flow 需要的验证码 / magic link / 激活链接”。 ## 2. 当前源码里的真实耦合 ### 2.1 后台轮询 payload 已经带着 OpenAI 过滤条件 `background/verification-flow.js` 当前在 `getVerificationPollPayload()` 里直接写死: - `senderFilters: ['openai', 'noreply', 'verify', 'auth', ...]` - `subjectFilters: ['verify', 'verification', 'code', '验证码', 'confirm', ...]` 这不是 provider 通用逻辑,而是 OpenAI flow 规则。 ### 2.2 内容脚本也已经写死 OpenAI / ChatGPT 正则 当前多个 provider 脚本里直接内嵌了 OpenAI / ChatGPT 识别: - `content/gmail-mail.js` - `content/mail-163.js` - `content/mail-2925.js` - `content/inbucket-mail.js` 例如: - `openai` - `chatgpt` - `verification` - `log-in code` - `strictChatGPTCodeOnly` 这意味着现在不是“通用 provider + OpenAI 规则”,而是“OpenAI 规则渗透进 provider 实现本身”。 ### 2.3 LuckMail 不能直接算进共享邮件层 LuckMail 当前还有一个额外边界:它不只是“邮箱提供商”,还绑定了 OpenAI 项目购邮与复用语义。 当前事实包括: - `DEFAULT_LUCKMAIL_PROJECT_CODE = 'openai'` - sidepanel 明确只展示 `openai` 项目的 LuckMail 邮箱 所以 LuckMail 当前应留在 OpenAI flow 内,不直接并入通用 `mailProviders`。 ## 3. 目标分层 ## 3.1 第一层:`mail provider driver` 这一层只负责 provider 访问与消息归一化,不理解具体网站业务。 职责包括: - 打开 provider 页面或请求 provider API - 等待页面 ready / 会话可用 - 列邮件、开邮件、取正文、删邮件 - 会话级去重 - 输出统一格式的消息对象 建议输出结构: ```js { providerId: 'gmail', messageId: 'abc123', receivedAt: 1710000000000, sender: 'OpenAI ', subject: 'Your code is 123456', previewText: 'Your code is 123456', normalizedText: 'your code is 123456', html: '...', links: ['https://...'], targetHints: ['user@example.com'], metadata: {}, } ``` 这一层不要再写: - “这是不是 OpenAI 邮件” - “是不是 ChatGPT 登录码” - “这个 code 是否必须 6 位” ## 3.2 第二层:`flow mail rules` 这一层由具体 flow 定义: - 要找的邮件类型 - 过滤条件 - 选择规则 - 提取规则 - 命中后的消费动作 建议接口: ```js flow.mailRules = { signupCode: { buildQuery(state) {}, matchMessage(message, state) {}, extractArtifact(message, state) {}, afterConsume(message, provider, state) {}, }, loginCode: { buildQuery(state) {}, matchMessage(message, state) {}, extractArtifact(message, state) {}, }, }; ``` 其中: - `buildQuery` 负责时间窗、目标邮箱、允许的发件人线索 - `matchMessage` 负责判定这是不是当前 flow 的邮件 - `extractArtifact` 负责提取 `code / magic-link / activation-link` - `afterConsume` 负责删除邮件、记录 cursor、保存已试 code ## 4. 建议的共享 mail service 接口 ```js mailService.poll({ providerId: 'gmail', rule: flow.mailRules.signupCode, state, maxAttempts: 5, intervalMs: 3000, }); ``` 内部流程: 1. provider driver 按 query 拉取候选消息 2. rule 决定哪封命中 3. rule 提取 artifact 4. service 返回统一结果 返回值示例: ```js { ok: true, artifact: { type: 'code', value: '123456', }, message: { ...normalizedMessage }, } ``` ## 5. OpenAI flow 当前应该拆出的规则 OpenAI 至少需要单独拆出这些规则文件: - `flows/openai/mail-rules/signup-code.js` - `flows/openai/mail-rules/login-code.js` - `flows/openai/mail-rules/add-email-code.js` 它们负责承接现在散落在这些地方的规则: - `verification-flow.js` 中的 sender / subject filters - `gmail-mail.js` / `mail-163.js` / `mail-2925.js` / `inbucket-mail.js` 中的 OpenAI / ChatGPT 正则 - `strictChatGPTCodeOnly` - Step 4 与 Step 8 不同的时间窗和目标邮箱逻辑 ## 6. provider driver 的拆分建议 ### 6.1 可以进入共享层的 provider 这些 provider 的访问方式本身有共享价值,可以做成共享 mail driver: - Gmail - 163 / 126 / 163 VIP - 2925 - Inbucket - iCloud Mail - Hotmail helper / Graph Mail - Cloud Mail / SkyMail ### 6.2 暂时不进入共享层的 provider - LuckMail:当前仍是 OpenAI 项目购邮与验证码轮询能力的一部分 如果未来第二个 flow 也明确复用 LuckMail,且复用的是“同一套 project / token / 生命周期”,再考虑把它抽出来。 ## 7. `registrationEmailState` 与邮件层的关系 `registrationEmailState` 负责“当前流程邮箱身份”,不是“provider 拉信规则”。 所以后续边界应是: - `registrationEmailState`:运行态身份记录 - `mail provider driver`:拉信能力 - `flow mail rules`:判定与提取 不要再在 `registrationEmailState` 或 provider driver 里夹带 OpenAI `add-email` 业务判断。 ## 8. 迁移顺序 1. 先把 `background/verification-flow.js` 里的查询构造迁到 `flows/openai/mail-rules/*` 2. 再把各 provider 脚本里的 OpenAI / ChatGPT 正则搬出到 rule 层 3. 保留 provider 里的“消息抓取 / 页面操作 / 删除策略” 4. 等第二个 flow 接入时,只新增它自己的 `mail-rules`,不改 Gmail / 163 / 2925 driver ## 9. 本文对应解决的缺口 本文主要补齐以下缺口: - “Mail polling 通用化”表述过于粗糙,没有说明 provider 与 rule 两层 - provider 内容脚本里已经嵌入 OpenAI 规则 - `strictChatGPTCodeOnly` 这类开关的归属边界不清 - LuckMail 当前其实还是 OpenAI flow 私有邮件能力,不是共享 provider