# 2925 account pool integration notes — 2026-05-11 Decision: abandon POP3/SMTP/IMAP forwarding to ClawEmail. Use the original extension's 2925 webmail/account-pool model directly. ## Account pool Secret file: ```text ~/.hermes/secrets/mail2925_accounts.txt ``` Format: ```text 邮箱----密码 user@2925.com----password ``` BOSS provided 20 accounts (`chickliu2021@2925.com` through `chickliu2040@2925.com`). Passwords are stored only in the local secret file with mode `0600`; never print or commit raw passwords. State file: ```text ~/.hermes/state/mail2925_accounts_state.json ``` State fields per account: ```json { "lastUsedAt": 0, "lastLoginAt": 0, "lastLimitAt": 0, "disabledUntil": 0, "lastError": "" } ``` ## Hard invariant: alias/account binding A generated 2925 registration address must be derived from the same 2925 account used to read mail. Example: ```text selected account: chickliu2021@2925.com allowed alias: chickliu2021rl9sxh@2925.com mail reader: logged in as chickliu2021@2925.com ``` Forbidden: ```text alias from chickliu2021*, but mailbox logged in as chickliu2022@2925.com ``` Gate before reading any code: ```text displayedMailboxEmail == selectedAccount.email alias.localPart startsWith selectedAccount.localPart ``` If the displayed mailbox email differs, clear 2925 cookies and force-login the selected account before continuing. ## Alias generation Use original extension rule, not Gmail-style plus tags: ```text baseLocal + randomSuffix(6) + @2925.com ``` Example: ```text chickliu2021@2925.com -> chickliu2021a8k2mz@2925.com ``` Do not generate `chickliu2021+tag@2925.com`. ## Account selection Pick among accounts that are: ```text enabled != false have password disabledUntil <= now ``` Sort by: ```text lastUsedAt ascending, then email ascending ``` This rotates accounts and avoids overusing one mailbox. ## Limit handling Detect 2925 limit messages: ```text 子邮箱已达上限 已达上限邮箱 子邮箱上限 邮箱已达上限 ``` On hit: ```text currentAccount.disabledUntil = now + 24h currentAccount.lastLimitAt = now currentAccount.lastError = reason switch to next available account terminate current OpenAI attempt and restart next round with a fresh alias ``` Do not continue the same OpenAI page after switching 2925 account; it risks mixing alias/account state. ## Local helper ```bash python3 scripts/mail2925_pool.py selftest python3 scripts/mail2925_pool.py list python3 scripts/mail2925_pool.py pick python3 scripts/mail2925_pool.py mark-limit chickliu2021@2925.com --reason '子邮箱已达上限邮箱' python3 scripts/mail2925_pool.py mark-login chickliu2021@2925.com ``` `pick` prints only email + generated alias; never prints passwords. Verified locally on 2026-05-11: ```json {"accounts":20,"aliasFailures":[],"secretMode":"0o600","ok":true} ``` ## Webmail flow to implement/use 1. Pick account and generate alias in one operation. 2. Open/login `https://2925.com/login/` or `https://2925.com/#/mailList`. 3. Verify displayed mailbox email equals picked account email. 4. Clear inbox before triggering OpenAI code. 5. Submit generated alias to OpenAI. 6. Poll 2925 inbox: 15 attempts, 15s interval. 7. Match OpenAI/auth/verify/code/login sender/subject/body; extract 6-digit code. 8. Open matching mail, extract body code, delete mail, return inbox. 9. Submit code; if invalid, add to rejectedCodes, resend, and continue polling. 10. On 2925 limit, mark current account cooldown and restart with next account.