Email integration connects Elmar's Microsoft 365 Outlook account to the Luci system via the MS Graph API. Emails are fetched, classified by project, summarized, and stored in a searchable SQLite database.
| Component | Path | Purpose |
|---|---|---|
graph_api.py |
~/workspace/scripts/graph_api.py |
MS Graph API client (auth, email, calendar, files) |
email_sync.py |
~/workspace/scripts/email_sync.py |
Daily email sync pipeline |
email_backfill.py |
~/workspace/scripts/email_backfill.py |
Backfill summaries for existing emails |
email_attachment_sync.py |
~/workspace/scripts/email_attachment_sync.py |
Download attachments for synced emails |
email.db |
~/workspace/email.db |
SQLite database of classified emails |
email-index skill |
~/.claude/skills/email-index/ |
Query interface for searching email.db |
Self-contained Python script with zero external dependencies (stdlib only). Handles its own OAuth via device code flow.
~/.graph-api-token.jsonpython graph_api.py login if refresh fails~/.cli-m365-msal.json)python graph_api.py login # One-time auth
python graph_api.py list-messages [--since DATE] # List emails
python graph_api.py read-message <id> # Read full email
python graph_api.py send-message --to ... --subject ... --body ...
python graph_api.py create-reply <id> --body ... # Draft reply
python graph_api.py send-draft <id> # Send a draft
python graph_api.py search --query "keyword" # Search Outlook
python graph_api.py search-files --query "..." # OneDrive/SharePoint search
python graph_api.py calendar [--start ...] [--end ...]
python graph_api.py upload-to-onedrive <local> <remote>
| Column | Type | Notes |
|---|---|---|
internet_message_id |
TEXT UNIQUE | RFC immutable key (survives moves/archive) |
conversation_id |
TEXT | Thread grouping |
subject |
TEXT | Email subject |
sender_email |
TEXT | Sender address |
sender_name |
TEXT | Display name |
received_date |
TEXT | ISO date |
project |
TEXT | Classified project name |
summary |
TEXT | 1-2 sentence summary |
confidence |
TEXT | high/medium/low |
has_attachments |
INTEGER | 0 or 1 |
graph_api.py read-message <graph-message-id> to fetch the full content on demand from Graph APISee 12-data-flows/email-pipeline for the full flow diagram.
email-sync (runs at 07:00 UTC weekdays)cowork/context/inbox-rules.md)email-index skillInbox rules are parsed from inbox-rules.md:
- Sender blocklist: Exact email matches and wildcard patterns (e.g., *@zapiermail.com)
- Subject skip patterns: Auto-skip emails with specific subject keywords
.email-sender-map.jsonemail_backfill.py enriches existing email.db records that lack summaries:
1. Fetches emails without summaries from email.db
2. Reads body from Graph API by internet_message_id
3. Sends to Gemini Flash for classification + summary
4. Updates email.db with results
- Rate limited: 1s between Graph API calls, batched Gemini calls
python ~/.claude/skills/email-index/query.py project "Project Heron"
python ~/.claude/skills/email-index/query.py search "MOI harith"
python ~/.claude/skills/email-index/query.py sender "stephan.spamer"
python ~/.claude/skills/email-index/query.py thread "AAQkAD..."
python ~/.claude/skills/email-index/query.py stats
python ~/.claude/skills/email-index/query.py recent --limit 10
python graph_api.py search --query "subject:keyword" --top 20
| Need | Tool |
|---|---|
| Past emails by project/person | email-index skill (queries email.db) |
| Full email body | email.db lookup then graph_api.py read-message <graph-message-id> |
| Live inbox / new emails | inbox-assist skill |
| Reply / draft / send | inbox-assist or graph_api.py |
| Ad-hoc Outlook search | graph_api.py search |
internet_message_id (RFC standard) is the primary key -- it survives email moves and archivingMission Control is the board for your delegated work: requests come in, Luci coordinates the next step, and evidence stays visible for review.
Luci is your always-on assistant for routing, status updates, and follow-through. Operators can still open deeper evidence when needed.