A completely local-first, conversational AI email assistant built with LangGraph, Ollama, and the Gmail API.
This agent runs directly from your terminal and allows you to manage your Gmail inbox using natural language. Because it uses a local LLM (Ollama), none of your email contents are sent to third-party AI providers like OpenAI or Anthropic — ensuring complete privacy.
The Modern Inbox Dilemma: Standard email clients rely entirely on rigid, exact-keyword matching (lexical search) and require manual triage to stay organized. If you are looking for emails about "learning," a standard client will miss an email from Udemy titled "Masterclass on Python" because the exact keyword isn't present. Furthermore, actionable items and deadlines are frequently buried inside long threads, forcing context-switching between your inbox and your to-do lists.
The Solution (New Integrations): I forked this project to transform it from a simple conversational email reader into an autonomous, semantically-aware inbox manager. I implemented the following major system upgrades:
- Semantic Search Engine (RAG): Replaced strict keyword reliance with a local ChromaDB vector database. The agent now mathematically embeds your emails, allowing you to search by abstract concept or meaning.
- Google Tasks Automation: Engineered an extraction pipeline that reads complex threads, identifies deadlines/action items, and autonomously syncs them to your Google Tasks board.
- Automated Daily Triage: Developed a standalone CLI batch job (
auto_triage.py) that acts as a background assistant—fetching emails, applying smart labels, executing task extraction, and sending a beautifully formatted HTML digest of its actions directly to your inbox.
- Search & List: Ask the agent to find specific emails (e.g., "Find my unread emails from Google"). The agent translates this into valid Gmail search queries under the hood.
- Read & Summarize: Read the full body of any email directly in your terminal. You can also ask the agent to summarize specific emails or your top 5 unread messages.
- Label Management: Organize your inbox naturally. Archive emails, mark them as read/unread, or star/unstar important messages without having to delete them (e.g., "Archive email 1", "Star the 3rd email").
- Attachment Handling:
- Read & Summarize: The agent automatically parses text from attached PDF, CSV, or TXT files so it can include them in its summaries and context.
- Download: Ask the agent to download an attachment, and it will be saved locally to a
downloadsdirectory. - Send with Attachments: Ask the agent to attach local files when composing an email.
- Send Emails: Compose and send emails using natural language. The agent will ask for any missing fields (To, Subject, Body) and will always ask for your confirmation before dispatching.
- Delete/Trash: Keep your inbox clean by asking the agent to delete specific emails or bulk-delete spam based on your descriptions (e.g., "Delete all emails from newsletters@spam.com").
- Beautiful CLI: Built with
TyperandRichfor styled panels, dynamic execution status updates, and a clean reading experience. - Google Tasks Sync: Ask the agent to "Extract tasks from this thread," and it will populate your connected Google Tasks list.
- Daily HTML Digests: The
auto_triage.pyscript runs silently, organizes specific categories of emails, and emails you a clean HTML summary log.
- Orchestration:
LangGraph(state machine for conversational routing and memory). - LLM Engine:
Ollamarunningllama3.1locally. - API Integration: Official Google
gmail-api,tasks-api. - Vector Database (RAG):
ChromaDB(Local) &sentence-transformers(all-MiniLM-L6-v2). - Interface:
Typer+Rich.
- Python 3.10+
- Ollama installed and running on your machine.
- A Google Cloud Platform (GCP) project with the Gmail API and Google Tasks API enabled.
Start Ollama and pull the required model:
ollama run llama3.1git clone <your-repo-url>
cd email-agent
# Create and activate a virtual environment
python -m venv .venv
# On Windows:
.venv\Scripts\activate
# On Mac/Linux:
source .venv/bin/activate
# Install dependencies
pip install -r requirements.txt- Go to the Google Cloud Console.
- Create a new project and enable the Gmail API.
- Go to APIs & Services > Credentials and create an OAuth client ID (Desktop Application).
- Download the JSON file, rename it to
credentials.json, and place it in the root of this project folder.Note:
credentials.jsonis safely ignored by.gitignoreso you don't accidentally push it to GitHub.
Start the agent by running:
python main.pyOn your first run, a browser window will open asking you to authorize the app. It requires the following scopes:
gmail.readonly(to read and search emails)gmail.send/gmail.compose(to send emails)gmail.modify(to move emails to the trash and apply labels)
Once authorized, a token.pickle file will be generated locally.
Here are a few things you can type in the interactive prompt:
- "List my unread emails."
- "Search for emails from github this week."
- "Read email number 2."
- "Summarize those emails."
- "Mark the first email as read and archive it."
- "Download the attachment from email 2."
- "Send an email to ansh@example.com about the meeting tomorrow and attach C:\path\to\report.pdf"
- "Delete the 3rd email."
Type exit or quit to leave the agent.
When to use it: Before you attempt to run any Semantic Searches (RAG). You should run this script periodically (e.g., once a week or every morning) to ensure your local vector database is up to date with your latest emails.
What happens: Standard search engines look for exact words. This script bypasses that limitation by downloading your recent emails and running them through a local sentence-transformers machine learning model. It converts the text into mathematical vectors and stores them safely in your local email_vector_db/ directory. This allows the AI to understand the meaning of your inbox.
How to run:
python scripts/vector_sync.pyNote: Depending on the volume of your inbox, the initial sync may take a few minutes as the local model processes the text.
When to use it: For automated, background inbox management. This script is designed to be run as a cron job or scheduled task. It fetches emails matching your criteria, applies labels, extracts actionable tasks, and emails you a clean, compiled HTML digest of its actions.
The digest email (rendered from templates/digest.html) includes:
- Agent actions — a log of what the triage performed (labels applied, tasks added, etc.)
- Email cards — for each matched email: the subject, sender, a one-sentence AI summary, and a direct "Open in Gmail" link (
https://mail.google.com/mail/u/0/#all/{message_id}) to jump straight to the source message
What happens: The script runs a single-pass LangGraph execution. It does not require user interaction. It processes the emails based on the flags you provide and immediately terminates upon completion.
Command Structure:
python auto_triage.py "CATEGORY_OR_KEYWORDS" [FLAGS]| Flag | Type | Default | Description |
|---|---|---|---|
CATEGORY |
String | Required | The target subject (e.g., "internships", "newsletters", "urgent"). |
--label |
String | None | Automatically applies a specified Gmail label (e.g., STARRED, IMPORTANT). |
--tasks |
Boolean | False | Triggers the LLM to extract deadlines/action items and sync to Google Tasks. |
--time |
String | 1d | Historical timeframe (e.g., 1d, 7d, 1m). |
--max |
Integer | 10 | The maximum number of emails to process in this batch. |
--semantic |
Boolean | False | Enables vector database (ChromaDB) queries for conceptual matches. |
Workflow A: The Lexical Triage (Standard) Perfect for catching exact phrases or specific senders over the last week.
python auto_triage.py "internship, application, offer" --label STARRED --tasks --time 7d --max 20Result: Fetches up to 20 emails from the last 7 days containing those exact words, stars them, adds extracted deadlines to Google Tasks, and emails you a summary.
Workflow B: The Semantic Triage (Advanced RAG) (Requires running vector_sync.py first)
python scripts/vector_sync.pyPerfect for finding abstract concepts where exact keywords might be missing.
python auto_triage.py "career progression and networking" --semantic --max 10Result: Queries your local vector database for 10 emails related to the concept of career progression, intelligently summarizes the abstract findings, and sends you a daily digest.
An alternative to auto_triage.py designed for cron jobs and scheduled tasks. Reads keywords from a .txt file and automatically runs vector_sync before every triage, keeping the semantic database current without manual intervention.
Create a plain text file with one keyword per line. Lines starting with # are ignored:
# internships.txt
internship
application
offer
remotepython auto_triage_file.py --file internships.txt --label STARRED --tasks --time 7d --max 20| Flag | Type | Default | Description |
|---|---|---|---|
--file, -f |
String | Required | Path to the .txt keywords file |
--label, -l |
String | None | Gmail label to apply (e.g., STARRED, IMPORTANT) |
--tasks, -t |
Bool | False | Extract deadlines into Google Tasks |
--time |
String | 1d | Search timeframe (1d, 7d, 1m) |
--max |
Integer | 20 | Max emails to process |
--semantic, -s |
Bool | False | Use vector DB for conceptual search |
--skip-sync |
Bool | False | Skip the automatic vector DB sync at startup |
The vector database is synced automatically on every run (unless --skip-sync is set), so you don't need to schedule vector_sync.py separately.
A PowerShell wrapper script (run_triage.ps1) is included for Windows Task Scheduler. It handles the full pipeline — starting Ollama if needed, waiting for it to be ready, then running the triage.
- Checks if
ollama.exeis running; if not, startsollama servein the background - Polls
http://localhost:11434/api/tagsup to 30 seconds until Ollama responds - Exits with code 1 if Ollama fails to start (triggers Task Scheduler retry)
- Runs
auto_triage_file.pywith your keyword file
-
Create your keywords file — one keyword per line,
#for comments:keywords.txt
-
Open Task Scheduler (Win+R →
taskschd.msc) -
Create Task with these settings:
Tab Setting Value General Name Email Agent Daily TriageRun whether user is logged on or not ✅ Run with highest privileges ✅ Triggers Daily at 7:00 AM(or your preferred time)Actions Program/script C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exeArguments -ExecutionPolicy Bypass -File "C:\path\to\email-agent\run_triage.ps1"Start in C:\path\to\email-agentConditions Stop if on battery ❌ (uncheck for laptops) Settings Restart on failure Every 1 minute, up to 3 times -
Test — right-click the task → Run, check the History tab for results.
Note: If Ollama is already set to start on login (default), the script detects it and skips the startup step.
EMAIL-AGENT/
├── agent/
│ ├── graph.py # Main LangGraph state machine & logic
│ └── __init__.py
├── email_vector_db/ # Local ChromaDB storage (Ignored in Git)
├── gmail/
│ ├── auth.py # OAuth2 authentication
│ ├── client.py # API client initialization
│ └── tools.py # Search, read, send, and label tools
├── scripts/
│ ├── vector_sync.py # Script to embed emails into ChromaDB
│ └── test_semantic.py # Sandbox script to test vector retrieval
├── tasks/
│ ├── tools.py # Google Tasks API wrappers
├── templates/
│ └── digest.html # Jinja2 HTML template for the daily triage digest email
├── utils/
│ └── parser.py # Attachment parsing (PDF, CSV, TXT)
├── vector/
│ ├── tools.py # ChromaDB initialization and search queries
├── auto_triage.py # CLI script for automated batch jobs (terminal keywords)
├── auto_triage_file.py # CLI script for automated batch jobs (keywords from .txt file)
├── run_triage.ps1 # PowerShell wrapper for Windows Task Scheduler (starts Ollama + runs triage)
├── main.py # Entry point for the interactive chat CLI
├── requirements.txt
└── .gitignoreYour credentials.json and token.pickle grant direct access to your Gmail account. Never commit these files to version control. They are included in the .gitignore by default. All LLM reasoning is done entirely locally via Ollama.