datawhalechina/hello-agents · error · ValueError
无法选择 INBOX (状态: {select_status!r})
Error message
无法选择 INBOX (状态: {select_status!r}) What it means
Raised in _fetch_via_imap() after login succeeds but mail.select() never returns 'OK' for any of the three attempted mailbox selectors: 'INBOX', '\"INBOX\"' (quoted), and 'INBOX' with readonly=True. The f-string in the raise is missing the .format/format-evaluation context issue — note the source uses f-string syntax so select_status is interpolated, showing the raw IMAP status (e.g. 'NO' or 'BAD'). Select failure at this point is almost always a server-side or protocol-level rejection of the SELECT command, not an auth problem (login already succeeded).
Source
Thrown at Co-creation-projects/Johnx-w-EmailDigestAgent/main.ipynb:302
"\n",
" def _fetch_via_imap(self, max_emails: int = 50, hours: int = 24) -> list:\n",
" server, port, username, password = self._read_imap_config()\n",
" if not username or not password:\n",
" raise ValueError(\"未配置邮箱信息\")\n",
"\n",
" console.print(f\"[dim] 连接 {server}:{port} 用户: {username}...[/dim]\")\n",
" mail = imaplib.IMAP4_SSL(server, port)\n",
" mail.login(username, password)\n",
"\n",
" # 选择收件箱 — 依次尝试: 无引号, 带引号, readonly\n",
" select_status = None\n",
" for name, rdonly in [(\"INBOX\", False), ('\"INBOX\"', False), (\"INBOX\", True)]:\n",
" select_status, select_data = mail.select(name, readonly=rdonly)\n",
" console.print(f\"[dim] select({name!r}, readonly={rdonly}) -> {select_status!r}[/dim]\")\n",
" if select_status == \"OK\":\n",
" break\n",
" if select_status != \"OK\":\n",
" raise ValueError(f\"无法选择 INBOX (状态: {select_status!r})\")\n",
"\n",
" since_date = (datetime.now() - timedelta(hours=hours)).strftime(\"%d-%b-%Y\")\n",
" search_criteria = f'(UNSEEN SINCE {since_date})'\n",
" status, message_ids = mail.search(None, search_criteria)\n",
" if status != \"OK\":\n",
" mail.logout()\n",
" return []\n",
"\n",
" ids = message_ids[0].split()\n",
" ids = list(reversed(ids))[:max_emails]\n",
" emails = []\n",
" for msg_id in ids:\n",
" try:\n",
" status, msg_data = mail.fetch(msg_id, \"(RFC822)\")\n",
" if status != \"OK\":\n",
" continue\n",
" raw_email = msg_data[0][1]\n",
" msg = email.message_from_bytes(raw_email)\n",View on GitHub (pinned to 606a07d341)
Solutions
- Log in to the mailbox web settings and confirm the IMAP/SMTP service is enabled (QQ Mail: 设置→账户→开启IMAP; Gmail: Settings→Forwarding and POP/IMAP→Enable IMAP).
- Inspect the printed debug line 'select(...) -> status' — a 'NO' usually includes a server message (visible in mail.error or the last response) indicating permission vs. nonexistent mailbox.
- List the actual mailboxes once with typ, data = mail.list() and SELECT the exact name the server reports instead of assuming 'INBOX'.
- If the server rejects read-write SELECT (e.g. shared/audited mailboxes), keep only the ('INBOX', True) readonly attempt.
- Retry after a minute if the provider throttles rapid successive sessions; close prior connections with mail.logout() in a finally block.
Example fix
// before
for name, rdonly in [("INBOX", False), ('"INBOX"', False), ("INBOX", True)]:
select_status, select_data = mail.select(name, readonly=rdonly)
if select_status == "OK":
break
if select_status != "OK":
raise ValueError(f"无法选择 INBOX (状态: {select_status!r})")
// after (discover the real mailbox name, prefer readonly)
typ, boxes = mail.list()
if typ != "OK":
raise ValueError(f"LIST 失败: {boxes!r}")
inbox = next((b.decode().rsplit('"', 2)[-2] for b in boxes if b.decode().upper().endswith('INBOX')), "INBOX")
select_status, select_data = mail.select(inbox, readonly=True)
if select_status != "OK":
raise ValueError(f"无法选择 {inbox} (状态: {select_status!r}, 响应: {select_data!r})") Defensive patterns
Strategy: fallback
Validate before calling
def select_inbox(mail: imaplib.IMAP4_SSL) -> None:
typ, boxes = mail.list()
names = [b.decode().rsplit('"', 2)[-2] for b in (boxes or []) if b]
for candidate in [n for n in names if n.upper().endswith("INBOX")] + ["INBOX"]:
status, _ = mail.select(candidate, readonly=True)
if status == "OK":
return
raise ValueError(f"无法选择 INBOX,服务器邮箱列表: {names}") Try / catch
try:
select_status, select_data = mail.select("INBOX", readonly=True)
except imaplib.IMAP4.abort as e:
# protocol/stream broken: reconnect once, then give up
raise RuntimeError(f"连接中断,请重试: {e}") from e
if select_status != "OK":
print(f"SELECT 失败: {select_data!r} — 请检查邮箱 IMAP 开关")
raise ValueError(f"无法选择 INBOX (状态: {select_status!r})") Prevention
- Enable IMAP service in the mailbox provider's web settings before running.
- Use mail.list() to discover the real mailbox name instead of hardcoding 'INBOX'.
- Prefer readonly=True SELECT for fetch-only workloads to avoid read-write rejections.
- Always mail.logout() in a finally block so repeated runs don't exhaust server sessions.
When it happens
Trigger: mail.select(name) returning status 'NO'/'BAD' for all three attempts: server rejects SELECT because the mailbox name is wrong or IMAP4rev1 namespace differs; server in a broken/quota-full state; some servers return non-OK to a read-write SELECT on a read-only mailbox, which the third (readonly=True) attempt usually covers; proxy/SSL middleboxes corrupting the command; Gmail accounts with IMAP disabled in settings also fail at SELECT/EXAMINE stage.
Common situations: QQ/163 mail with IMAP service not enabled in web settings; Gmail with IMAP disabled under Forwarding and POP/IMAP; mailbox name localized or namespaced (e.g. 'INBOX' not exposed, or server requires '"INBOX"' quoting); server temporary failure after too many rapid SELECT connections; antivirus/firewall mangling the TLS stream causing protocol desync.
Related errors
AI-assisted analysis of datawhalechina/hello-agents@606a07d341 (2026-08-14).
Data as JSON: /api/errors/e67628d4570b3a08.
Report an issue: GitHub.