{"record":{"id":"62ca9395f1bd201b","repo":"datawhalechina/hello-agents","slug":"error-62ca93","errorCode":null,"errorMessage":"未配置邮箱信息","messagePattern":"未配置邮箱信息","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"Co-creation-projects/Johnx-w-EmailDigestAgent/main.ipynb","lineNumber":288,"sourceCode":"    \"        username = os.getenv(\\\"IMAP_USERNAME\\\") or \\\"\\\"\\n\",\n    \"        password = os.getenv(\\\"IMAP_PASSWORD\\\") or \\\"\\\"\\n\",\n    \"        if not (username and password and server):\\n\",\n    \"            try:\\n\",\n    \"                with open(\\\"config/email_config.json\\\", \\\"r\\\", encoding=\\\"utf-8\\\") as f:\\n\",\n    \"                    cfg = json.load(f)\\n\",\n    \"                imap_cfg = cfg.get(\\\"imap\\\", {})\\n\",\n    \"                server = server or imap_cfg.get(\\\"server\\\", \\\"imap.qq.com\\\")\\n\",\n    \"                port = port or imap_cfg.get(\\\"port\\\", 993)\\n\",\n    \"                username = username or imap_cfg.get(\\\"username\\\", \\\"\\\")\\n\",\n    \"                password = password or imap_cfg.get(\\\"password\\\", \\\"\\\")\\n\",\n    \"            except FileNotFoundError:\\n\",\n    \"                pass\\n\",\n    \"        return server or \\\"imap.qq.com\\\", port or 993, username, password\\n\",\n    \"\\n\",\n    \"    def _fetch_via_imap(self, max_emails: int = 50, hours: int = 24) -> list:\\n\",\n    \"        server, port, username, password = self._read_imap_config()\\n\",\n    \"        if not username or not password:\\n\",\n    \"            raise ValueError(\\\"未配置邮箱信息\\\")\\n\",\n    \"\\n\",\n    \"        console.print(f\\\"[dim]  连接 {server}:{port}  用户: {username}...[/dim]\\\")\\n\",\n    \"        mail = imaplib.IMAP4_SSL(server, port)\\n\",\n    \"        mail.login(username, password)\\n\",\n    \"\\n\",\n    \"        # 选择收件箱 — 依次尝试: 无引号, 带引号, readonly\\n\",\n    \"        select_status = None\\n\",\n    \"        for name, rdonly in [(\\\"INBOX\\\", False), ('\\\"INBOX\\\"', False), (\\\"INBOX\\\", True)]:\\n\",\n    \"            select_status, select_data = mail.select(name, readonly=rdonly)\\n\",\n    \"            console.print(f\\\"[dim]  select({name!r}, readonly={rdonly}) -> {select_status!r}[/dim]\\\")\\n\",\n    \"            if select_status == \\\"OK\\\":\\n\",\n    \"                break\\n\",\n    \"        if select_status != \\\"OK\\\":\\n\",\n    \"            raise ValueError(f\\\"无法选择 INBOX (状态: {select_status!r})\\\")\\n\",\n    \"\\n\",\n    \"        since_date = (datetime.now() - timedelta(hours=hours)).strftime(\\\"%d-%b-%Y\\\")\\n\",\n    \"        search_criteria = f'(UNSEEN SINCE {since_date})'\\n\",\n    \"        status, message_ids = mail.search(None, search_criteria)\\n\",","sourceCodeStart":270,"sourceCodeEnd":306,"githubUrl":"https://github.com/datawhalechina/hello-agents/blob/606a07d341a47be773fab7f4b71177f53f96b2c3/Co-creation-projects/Johnx-w-EmailDigestAgent/main.ipynb#L270-L306","documentation":"Raised by _fetch_via_imap() in the EmailDigestAgent notebook when _read_imap_config() returns an empty username or password. _read_imap_config() resolves credentials from explicit arguments, then an 'imap' section of a config file, falling back to empty strings (username=\"\", password=\"\") — it never raises for missing config, so the blank credentials surface here as ValueError('未配置邮箱信息'). It is a configuration error, not an IMAP protocol failure.","triggerScenarios":"Calling agent.run() with use_demo=False (or instantiating the email tool in live mode) when: no username/password arguments were passed, and the config file (e.g. config.json/.yaml read inside _read_imap_config) does not exist (FileNotFoundError is swallowed by 'except FileNotFoundError: pass') or its imap section lacks username/password keys. Defaults only cover server ('imap.qq.com') and port (993), never credentials.","commonSituations":"Fresh clone of the project without copying the config template; config file present but keys named differently (e.g. 'user'/'pass' instead of 'username'/'password'); QQ Mail users forgetting to generate an authorization code (QQ Mail requires an app-specific IMAP code, not the account password); running the notebook from a directory where the relative config path doesn't resolve.","solutions":["Create the config file the notebook expects with an 'imap' section containing server/port/username/password keys, matching the exact key names read by _read_imap_config().","For QQ Mail, enable IMAP in mailbox settings and use the 16-character authorization code (授权码) as the password, not the login password.","Alternatively pass username= and password= directly to the tool/constructor call so they don't depend on file config.","If you just want to see the agent run, set use_demo=True to use demo_emails and skip IMAP entirely.","Verify the config file is being found: the code silently ignores FileNotFoundError, so confirm the exact path _read_imap_config() opens and that the notebook cwd contains it."],"exampleFix":"// before (config missing -> silent empty credentials)\ntry:\n    cfg = json.loads(cfg_path.read_text())\n    imap_cfg = cfg.get(\"imap\", {})\n    username = username or imap_cfg.get(\"username\", \"\")\n    password = password or imap_cfg.get(\"password\", \"\")\nexcept FileNotFoundError:\n    pass  # silently proceeds, later raises 未配置邮箱信息\n\n// after (fail early with actionable message)\ntry:\n    cfg = json.loads(cfg_path.read_text())\nexcept FileNotFoundError:\n    raise ValueError(f\"未找到配置文件 {cfg_path}，请复制模板并填写 imap 节点\") from None\nimap_cfg = cfg.get(\"imap\", {})\nusername = username or imap_cfg.get(\"username\", \"\")\npassword = password or imap_cfg.get(\"password\", \"\")","handlingStrategy":"validation","validationCode":"def has_imap_credentials(username: str, password: str, cfg_path: Path) -> bool:\n    if username and password:\n        return True\n    if not cfg_path.exists():\n        return False\n    imap_cfg = json.loads(cfg_path.read_text()).get(\"imap\", {})\n    return bool(imap_cfg.get(\"username\") and imap_cfg.get(\"password\"))\n\n# before agent.run(use_demo=False):\nif not has_imap_credentials(username, password, cfg_path):\n    raise SystemExit(\"缺少 IMAP 凭据：请在配置文件 imap 节点填写 username/password，或改用 use_demo=True\")","typeGuard":null,"tryCatchPattern":"try:\n    result = agent.run(hours=24)\nexcept ValueError as e:\n    if \"未配置邮箱信息\" in str(e):\n        # config problem: point user at the config file, never retry\n        print(f\"配置缺失: {e} — 请填写 imap username/password\")\n    raise","preventionTips":["Copy the config template and fill the imap section before the first live run.","Use provider-specific IMAP authorization codes (QQ/163 授权码), not the login password.","Fail fast in _read_imap_config() on FileNotFoundError instead of returning empty strings.","Ship a startup check that validates credentials exist (non-empty) and logs which key is missing."],"tags":["configuration","imap","email","credentials","python"],"backgroundTag":null,"analyzedSha":"606a07d341a47be773fab7f4b71177f53f96b2c3","analyzedAt":"2026-08-14T22:57:27.446Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}