Add 2925 account pool binding helper
This commit is contained in:
@@ -0,0 +1,153 @@
|
||||
# 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.
|
||||
Reference in New Issue
Block a user