Full implementation of the Howl email triage system: - Microsoft Graph API integration with MSAL auth (client-credentials and delegated modes) - Claude LLM classification via tool use for structured output - PostgreSQL database with customers, vendors, whitelist, and email_log tables - Alembic migration for full schema - APScheduler daemon with graceful shutdown - Typer CLI (run, dry-run, status commands) - Business rule classifier with overrides (whitelist protection, low-confidence fallback) - Action executor (move to folders, flag, escalate with webhook) - 35 passing unit tests - README, SETUP, and NEXT_STEPS documentation Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4.4 KiB
4.4 KiB
Howl
An M365 email management daemon that uses the Microsoft Graph API and Claude AI to automatically classify and route incoming email based on your customer, vendor, and whitelist database.
How it works
Inbox (M365)
│
▼
Graph API polls for unread mail
│
▼
PostgreSQL lookup — is the sender a customer, vendor, or trusted contact?
│
▼
Claude (LLM) classifies the email using sender context + body content
│
▼
Business rules applied (whitelist always wins, low-confidence → hold for review)
│
▼
Action taken: move to folder / flag / escalate with notification
│
▼
email_log table records every decision for audit and retry
Features
- Supports both shared mailboxes (app-only, no user login) and personal mailboxes (delegated device-code auth)
- No emails are ever deleted — only moved, flagged, or escalated
- Dry-run mode — analyze and log without touching any email
- Idempotent — safe to restart; already-processed messages are skipped
- Automatic retry — failed messages are retried on the next poll cycle
- Full audit log — every classification, confidence score, and action is stored in PostgreSQL
Folder routing
| Sender type | LLM classification | Action |
|---|---|---|
| Customer | Inquiry / correspondence | Move to Customers folder |
| Vendor | Invoice / notification | Move to Vendors folder |
| Whitelist | Trusted contact | Mark read, stay in Inbox |
| Any | Urgent / escalation | Move to Escalate + webhook notification |
| Any | Uncertain (low confidence) | Move to Needs Review |
| Unknown | Spam / newsletter | Move to Junk Email |
Quick start
# 1. Create and activate a virtual environment
python3 -m venv .venv && source .venv/bin/activate
# 2. Install dependencies
pip install -e ".[dev]"
# 3. Configure environment
cp .env.example .env
# Edit .env with your Azure, Anthropic, and PostgreSQL credentials
# 4. Run database migrations
alembic upgrade head
# 5. Test with dry-run (no email mutations)
howl dry-run --limit 10
# 6. Start the daemon
howl run
CLI commands
| Command | Description |
|---|---|
howl run |
Start the daemon (blocking, polls on schedule) |
howl dry-run [--limit N] |
Classify up to N emails, log results, take no action |
howl status [--limit N] |
Display recent email_log entries in a table |
Project structure
howl/
├── howl/
│ ├── config.py # All configuration (pydantic-settings + .env)
│ ├── main.py # CLI entry point (Typer)
│ ├── logging_config.py # structlog setup (JSON or text)
│ ├── db/
│ │ ├── engine.py # Async SQLAlchemy engine
│ │ ├── models.py # ORM models
│ │ └── queries.py # lookup_sender(), email log helpers
│ ├── graph/
│ │ ├── auth.py # MSAL token provider (client-credentials or delegated)
│ │ └── client.py # Graph API: list, read, move, flag messages
│ ├── llm/
│ │ ├── client.py # Anthropic SDK wrapper with retry
│ │ ├── prompts.py # Prompt builder (system prompt + per-email user turn)
│ │ └── schemas.py # EmailClassification model + tool definition
│ ├── pipeline/
│ │ ├── processor.py # EmailProcessor — orchestrates the full pipeline
│ │ ├── classifier.py # Business rule overrides on LLM output
│ │ └── actions.py # ActionExecutor — Graph mutations + webhook
│ └── daemon/
│ └── scheduler.py # APScheduler poll loop + graceful shutdown
├── migrations/ # Alembic database migrations
├── tests/ # Unit and integration tests
├── .env.example # Configuration template
├── SETUP.md # Detailed setup and configuration guide
└── NEXT_STEPS.md # Roadmap and future improvements
Running tests
pytest tests/ -q # All tests (no external services needed)
pytest tests/ -q -m "not integration" # Unit tests only (default)
pytest tests/ -q -m integration # Requires real M365 + Anthropic credentials
Requirements
- Python 3.11+
- PostgreSQL 14+
- Microsoft Azure app registration with
Mail.Read+Mail.ReadWritepermissions - Anthropic API key