MailMind: An AI Agent That Actually Handles Email Scheduling
Why I built this
Scheduling meetings over email is surprisingly painful.
You send one mail, then it turns into a long thread:
“Are you free Tuesday?”
“No, what about Wednesday?”
“Let’s do next week.”
…and it just keeps going.
The problem isn’t email itself — it’s that we’re using an unstructured system to solve a structured task.
Most tools try to fix this, but they all require behavior change:
- Calendly → click a link
- AI assistants → draft replies, but don’t act
- Bots → break in real conversations
I wanted to try something different:
what if the system just worked inside email, without changing how people use it?
What MailMind does
MailMind is an AI agent that joins an email thread and handles scheduling end-to-end.
You just CC it once.
From there, it:
- reads the conversation
- understands availability from natural language
- follows up if something is unclear
- finds a common time
- creates a calendar event
- sends confirmations
No links. No UI. No extra steps.
Everything happens inside the same email thread.
How it actually works
At a high level, the system is event-driven.
An incoming email triggers the entire pipeline:
- Gmail pushes an event
- backend fetches full thread data
- agent processes it
- system decides what to do next
Instead of writing this as a linear script, I used a state-based agent loop.
Each step in the flow is a node:
- classify the email
- extract availability
- check if something is missing
- compute overlaps
- generate a response
The agent moves between these states depending on what it sees in the thread.
LLM + deterministic logic
The LLM is not running the whole system.
It’s only used where natural language is involved:
- understanding emails
- detecting ambiguity
- rewriting responses
Everything else is deterministic:
- time parsing
- overlap calculation
- slot ranking
- calendar operations
This separation makes the system more reliable.
Maintaining context
Each email thread is treated as a persistent session:
- who has replied
- what time slots they gave
- who is pending
- preferences (like “no Fridays”)
This state is stored in SQLite and updated after every email.
Choosing the best time
A scoring function ranks slots based on:
- attendance
- preferences
- priority participants
- time optimization
The system selects the most practical option, not just the first valid one.
Safety layer
Before sending any email:
- draft goes to Telegram
- approve / reject / edit
- auto-send fallback
Tech Stack
- Python
- FastAPI
- LangGraph
- Gemini 2.0 Flash
- SQLite
- React
- Gmail API
- Google Calendar API
- Telegram Bot API
Final thought
Most AI tools assist.
This one acts.
It takes something messy (email threads) and turns it into a structured, executable workflow.


That’s where AI becomes actually useful.
Top comments (2)
this is the right shape imo: Gmail push wakes the pipeline, then the agent only gets involved where language is messy.
the part i'd be most curious about is the boring reliability layer. are you keeping a per-user historyId cursor plus processed thread/message ids so Pub/Sub retries or overlapping Gmail history results don't re-run the scheduler? and do you have a periodic history.list catch-up for the cases where push is delayed/dropped?
Totally fair question, and you’re exactly right about the reliability layer.
In this current version, I’m still on IMAP UNSEEN polling with per-thread SQLite checkpointing/state, so I’m not yet using a per-user
historyIdcursor + processed message/thread ID dedupe for Pub/Sub retries/overlaps.And yes, I agree on catch-up: a periodic
history.listreconciliation loop for delayed/dropped push events is the next reliability upgrade on my roadmap.Appreciate you calling this out, this is exactly the kind of “boring but critical” hardening I’m focused on next.