Files
FlowPilot/docs/多注册流程邮件分层设计.md
T
2026-05-13 00:52:10 +08:00

6.1 KiB
Raw Blame History

多注册流程邮件分层设计

本文专门解决“邮件轮询虽然看起来像公共能力,但实际 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 / 会话可用
  • 列邮件、开邮件、取正文、删邮件
  • 会话级去重
  • 输出统一格式的消息对象

建议输出结构:

{
  providerId: 'gmail',
  messageId: 'abc123',
  receivedAt: 1710000000000,
  sender: 'OpenAI <noreply@openai.com>',
  subject: 'Your code is 123456',
  previewText: 'Your code is 123456',
  normalizedText: 'your code is 123456',
  html: '<html>...</html>',
  links: ['https://...'],
  targetHints: ['user@example.com'],
  metadata: {},
}

这一层不要再写:

  • “这是不是 OpenAI 邮件”
  • “是不是 ChatGPT 登录码”
  • “这个 code 是否必须 6 位”

3.2 第二层:flow mail rules

这一层由具体 flow 定义:

  • 要找的邮件类型
  • 过滤条件
  • 选择规则
  • 提取规则
  • 命中后的消费动作

建议接口:

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 接口

mailService.poll({
  providerId: 'gmail',
  rule: flow.mailRules.signupCode,
  state,
  maxAttempts: 5,
  intervalMs: 3000,
});

内部流程:

  1. provider driver 按 query 拉取候选消息
  2. rule 决定哪封命中
  3. rule 提取 artifact
  4. service 返回统一结果

返回值示例:

{
  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