We built an autonomous agent that watches your inbox for you.
It reads and sorts incoming mail on its own, leaving only what you need to see in the inbox, and even prepares reply drafts.
It is not a tool that summarizes received mail in one line. It marks as read the mail you needn't read, drafts replies for work mail, archives it to the client's project folder, and learns rules from your feedback — closer to a capable colleague who tidies your mail alongside you.
The core value of this agent is automatic mark-as-read — what we call triage.
Dozens of newsletters, automated alerts, and system emails pile up every day and bury the mail that actually matters.
The agent judges whether each message is one you must read or act on, and marks the rest as read on its own. Only the mail a person needs to see remains in the inbox. (Reversible anytime.)
Most tools follow fixed rules — "sender/keyword → label/filter." MailAgent is different because it is an agent.
Not keyword matching — the LLM reads the full body and decides whether it needs to be read.
For work mail, it learns your voice and drops a reply draft into the drafts folder. (You do the sending.)
"Ignore mail like this" — one sentence becomes a persistent rule, applied from the next poll on.
Cron polls the inbox every few minutes, and the LLM classifies and acts on each thread in one pass.
Cron checks the inbox periodically (an idempotent cursor prevents duplicates)
Judges category, need-to-read, need-to-reply, and draft as JSON in one pass
Mark unneeded mail read · draft replies for work mail · save to project Drive
See results in a web dashboard/chat; a person sends from Gmail
Every state (threads, drafts, rules, read/restore) is persisted to a local DB and AuditLog — undoable and traceable.
A category is the starting point for "how to handle this mail" — need-to-read is judged by content, not bound to the category.
| Category | What kind of mail | Handling |
|---|---|---|
| onboarding | New-customer entry mail — sign-ups, setup, etc. | Reply draft + Drive archive |
| dev | Customer↔dev back-and-forth (bugs, requests, QA) | Reply draft + Drive archive |
| internal | Internal alerts, to be summarized | Included in the daily summary (no draft) |
| ignore | Spam, newsletters, automated mail | Ignore (mark-as-read candidate) |
So conversations don't scatter across clients, work mail is saved as a Google Doc in the project's Drive folder.
The web review chat is the learning channel — natural-language feedback becomes a persistent rule injected into the next batch classification.
The review agent is a LangGraph tool-loop — rules are stored as structured DB memory and the LLM interprets & applies them (no keyword matching).
A criterion you give once accrues as a rule, so the same judgment is never asked again.
| Rule type | What it learns |
|---|---|
| sender_rule | Handling for a specific sender/domain (fix a category, ignore, etc.) |
| category_rule | Adjusting the classification criteria |
| read_rule | Conditions for mail that needn't be read (auto mark-as-read) — the heart of triage |
| draft_rule | Whether to draft and what to include |
| tone_rule | Reply voice & tone |
Rules are stored as shared memory (SoT), and every change is traced in AuditLog with its source.
| Ability | Tool | What it does |
|---|---|---|
| 👁 View | list_recent_classifications · get_thread_detail | Check recent classification results & read status |
| 🧠 Learn | write_rule / update_rule / delete_rule | Store/update/deactivate rules (upsert · soft-delete) |
| ✂ Correct | set_thread_category | One-off fix for a single thread (no generalization) |
| 📥 Read | mark_thread_read / mark_thread_unread | Mark an individual thread read / restore to unread |
| 🗂 Archive | list_projects · list_pending_archive · archive_thread_to_project | Save pending mail with a person-assigned project |
It only drafts; a person does the actual sending and final call. Mis-send risk 0. Uses only read + draft scopes (no send scope).
Auto mark-as-read can be restored to unread, and every read/restore & rule change is recorded in AuditLog.
An idempotent cursor skips already-seen threads, and a draft cap (--max-drafts) blocks mass generation on the first run (the overflow runs next time).
If a project match is uncertain, it doesn't force a save (pending); if need-to-read is uncertain, it conservatively treats it as "must read."
Based on an inbox of dozens to hundreds a day, savings vs. manual handling (varies with mail volume).
| Task | Before (manual) | After (MailAgent) | Savings |
|---|---|---|---|
| Skimming & clearing unneeded mail | 20–40 min/day | Auto mark-as-read | Mostly automated |
| Writing reply drafts | 5–15 min each | Review & edit 2–3 min | ~70% |
| Archiving customer mail | 3–5 min each | Auto-saved | 100% automated |
| Missing important mail | Buried & delayed | Always visible in the inbox | Miss risk ↓ |
cron + Django management command (poll_inbox) — the lightest broker-free batch
OpenRouter (OpenAI-compatible) · anthropic/claude-sonnet-4 — swap models with one key
LangGraph tool-loop (StateGraph · tool binding) · LangChain · LangSmith tracing
Django · Django admin supervision console · web review chat UI
PostgreSQL — persists threads, drafts, rules, audit logs (local DB = SoT)
Gmail · Drive · Docs (standarda-core client) · OAuth gmail.modify
Design principle — "autonomy that doesn't send": leave the final call to a person while stripping away the repetitive labor before it
Promote trusted categories from drafts to auto-send.
As rules grow, select only the relevant ones to inject into the prompt.
An agent that filters better as mail piles up