Files
codex-oauth-plus-onboarding…/references/mail2925-account-pool-integration-2026-05-11.md
T

3.5 KiB

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:

~/.hermes/secrets/mail2925_accounts.txt

Format:

邮箱----密码
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:

~/.hermes/state/mail2925_accounts_state.json

State fields per account:

{
  "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:

selected account: chickliu2021@2925.com
allowed alias:     chickliu2021rl9sxh@2925.com
mail reader:       logged in as chickliu2021@2925.com

Forbidden:

alias from chickliu2021*, but mailbox logged in as chickliu2022@2925.com

Gate before reading any code:

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:

baseLocal + randomSuffix(6) + @2925.com

Example:

chickliu2021@2925.com -> chickliu2021a8k2mz@2925.com

Do not generate chickliu2021+tag@2925.com.

Account selection

Pick among accounts that are:

enabled != false
have password
disabledUntil <= now

Sort by:

lastUsedAt ascending, then email ascending

This rotates accounts and avoids overusing one mailbox.

Limit handling

Detect 2925 limit messages:

子邮箱已达上限
已达上限邮箱
子邮箱上限
邮箱已达上限

On hit:

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

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:

{"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.