Repository navigation
v1.2.0 — read-only inbox fetch & triage
The receive side of the mail lifecycle lands: two new tools close the inbox-triage loop.
Added
office_inbox_fetch— read-only IMAP pull of the newest messages (envelope, short body snippet, attachment list). Bodies are fetched with BODY.PEEK so \Seen is never set; no flags are written, nothing is deleted. Results are appended to a local JSONL index (~/.dsh/office/mail/index.jsonl, metadata only) with messageId dedup — the shared data layer for the upcoming archive and stats tools. Host presets for qq / foxmail / 163 / 126 / gmail / outlook / hotmail / live are auto-derived from the account address; other providers setimapHost. Credentials go through theDSH_IMAP_PASSenv var, never config files. QQ / 163 / 126 require an IMAP authorization code, not the login password.office_inbox_triage— deterministic classification of the fetched index into four buckets: todo (deadlines, interviews, offers, verification codes), notice (announcements, reminders, .edu.cn senders), subscription (bulk headers, no-reply senders, known bulk domains), personal (1:1 mail, replies). Every verdict carries its rule evidence; low/medium-confidence items are listed inneedsReviewfor semantic refinement by the agent. Also emitssubscriptionSenders, a per-sender frequency table that will feed the v1.5 unsubscribe advisor.
Security posture
IMAP is strictly read-only; local persistence is metadata plus a 300-character snippet (no full text, no attachment content); mail bodies are treated as untrusted input per SECURITY.md.
Under the hood
ImapFlow 1.4.1 + mailparser 3.7 (both Postal Systems, MIT — the same lineage as the existing nodemailer SMTP path). Tests grew from 46 to 71, including 25 inbox cases: provider presets, classification rules and their priority order, index dedup, and an isolated-office-home triage e2e.
Full scenario map and the v1.3-v1.5 roadmap (archive, stats, unsubscribe advisor): docs/MAIL-SCENARIOS.zh-CN.md.