# 2925 mail provider rules from original extension — 2026-05-11 Source inspected: original extension repo `codex-oauth-automation-extension` (`mail2925-utils.js`, `managed-alias-utils.js`, `background/generated-email-helpers.js`, `background/mail-2925-session.js`, `background/verification-flow.js`, `content/mail-2925.js`, related tests). ## Provider modes `mailProvider=2925` has two distinct modes: - `mail2925Mode=provide` (default): 2925 provides the registration email via a managed alias. - `mail2925Mode=receive`: registration email comes from another generator/manual path; 2925 is only the mailbox used to receive/poll mail. For replacing ClawEmail in OpenAI/Codex signup, prefer `provide` first. ## Alias generation 2925 does **not** use Gmail-style plus tags. ```text base: yourname@2925.com alias: yourname + randomSuffix(6) + @2925.com ``` Examples: ```text abc@2925.com -> abcxk39qz@2925.com ``` Provider ownership check: ```text domain == 2925.com candidate local == base local OR candidate local startsWith(base local) ``` ## Account pool Import format: ```text 邮箱----密码 user1@2925.com----[REDACTED_PASSWORD_1] user2@2925.com----[REDACTED_PASSWORD_2] ``` Normalized account fields: ```json { "id": "...", "email": "xxx@2925.com", "password": "...", "enabled": true, "lastUsedAt": 0, "lastLoginAt": 0, "lastLimitAt": 0, "disabledUntil": 0, "lastError": "" } ``` Available account gate: ```text email present password present enabled != false not cooling down ``` Selection policy: choose the available account with the oldest `lastUsedAt`; tie-break by email. ## Login/session gates URLs/domains: ```text mail list: https://2925.com/#/mailList login: https://2925.com/login/ cookie domains: 2925.com, www.2925.com, mail2.xiyouji.com cookie origins: https://2925.com, https://www.2925.com, https://mail2.xiyouji.com ``` Force relogin flow: 1. Clear 2925 cookies on the domains/origins above. 2. Wait ~3 seconds. 3. Open login URL. 4. Wait ~3 seconds before checking fields. 5. Ensure agreement/remember checkboxes if present. 6. Fill email, wait ~150ms. 7. Fill password, wait ~200ms + 1000ms. 8. Click login. 9. Wait up to 40 seconds for mailbox view. Critical gate: the displayed mailbox email at the top of the 2925 page must match the selected account. If mismatched and account pool is enabled, clear/relogin to the target account. If pool is disabled, stop rather than polling the wrong mailbox. ## Limit/cooldown handling Detect page/error text matching: ```text 子邮箱已达上限 已达上限邮箱 子邮箱上限 邮箱已达上限 ``` When detected: - Prefix/internal class: `MAIL2925_LIMIT_REACHED::...` - If account pool disabled: stop the flow. - If current account is known: set `lastLimitAt=now`, `disabledUntil=now+24h`, `lastError=reason`. - Pick the next available account excluding the current id. - Force relogin to the next account. - End the current attempt/thread; next retry should start fresh. Cooldown constant: `24 * 60 * 60 * 1000`. ## Verification polling For 2925, both signup and login verification use: ```text maxAttempts = 15 intervalMs = 15000 ``` Total mailbox wait window is about 225 seconds per poll round. Signup filters: ```text sender: openai, noreply, verify, auth, duckduckgo, forward subject: verify, verification, code, 验证码, confirm ``` Login filters: ```text sender: openai, noreply, verify, auth, chatgpt, duckduckgo, forward subject: verify, verification, code, 验证码, confirm, login ``` `receive` mode enables weak target-email matching: if the preview/body contains an explicit target email, it must match the current registration/login email. `provide` mode does not require this because the generated registration email belongs to the current 2925 mailbox. ## Anti-stale-code rules Prefer this sequence over ClawEmail-style newest-list polling: 1. Before sending/requesting a fresh OpenAI code, pre-clear the 2925 inbox when no reliable `filterAfterTimestamp` is available. 2. Request/resend the OpenAI code. 3. Poll inbox with refresh cycles. 4. For each candidate mail: open it, read preview/body, extract 6-digit code, delete the mail, return to inbox. 5. Maintain `seenCodes` and `rejectedCodes` to avoid resubmitting old/invalid codes. 6. If OpenAI marks a code invalid, add it to `rejectedCodes`, request a new code if allowed, and continue polling. 7. After a successful verification step, trigger best-effort delete-all cleanup for 2925. Important: 2925 page list ordering should not be trusted as the only freshness signal. The original extension relies heavily on pre-clear + delete-after-read + seen/rejected-code sets. ## Recommended Hermes runner design For a 2925-backed Codex OAuth runner, add env/config like: ```text MAIL_PROVIDER=2925 MAIL2925_MODE=provide MAIL2925_ACCOUNTS_FILE=/path/to/2925-accounts.jsonl-or-txt MAIL2925_USE_ACCOUNT_POOL=true ``` Then implement gates: ```text select available 2925 account login/ensure session verify displayed mailbox email == selected account email pre-clear inbox generate alias: baseLocal + 6 random lowercase/digits + @2925.com submit alias to OpenAI poll 2925, delete after read, strict 6-digit extraction submit code on invalid code: rejectedCodes + resend + repoll on limit text: disable account 24h and switch account; do not continue current OpenAI attempt ``` ## Why this is better than ClawEmail for this class - No sub-mailbox creation step. - No external receive permission/Dashboard API gate. - No `mail-cli` profile ambiguity. - Delete-after-read and pre-clear reduce old-code pollution. - Account pool/cooldown explicitly handles 2925 per-account limits. Risk: single 2925 account can hit sub-mailbox limits, so account pool support is not optional for high-volume runs.