AI-native email & calendar client over JMAP and CalDAV
Project description
Courier
AI-native email & calendar client over JMAP and CalDAV.
Your AI agent deserves its own email client — not an adapter wrapping a human one.
The Problem
Every AI agent framework connects to email and calendar by wrapping human-facing apps. MCP servers adapt web UIs. Osascript automates native mail clients. Browser tools click through webmail. Each introduces friction because the agent is fighting an interface designed for someone else.
Courier takes a different approach: connect directly to the open protocols (JMAP for email, CalDAV for calendar) as a first-class client — a peer alongside your human apps, not a wrapper around them.
What Makes It Different
- Context-window-optimized output — emails are structured for AI consumption, not HTML rendering
- Session state & watermarks — "what's new?" is a first-class operation that persists between sessions
- Triage classification — emails arrive pre-sorted: urgent, needs_reply, actionable, fyi, bulk
- Batch-first operations — archive 15 emails in one call, not 15 separate requests
- Sane timezone handling — CalDAV with proper TZID normalization and recurrence expansion
- Composable — higher-order operations like "find all emails from this person and summarize the thread"
Quick Start
pip install ai-courier
# Configure your Fastmail account
courier setup
# Check your inbox (triaged by priority)
courier inbox
# What's new since last check?
courier new
# Today's calendar
courier today
# Find free time
courier free
As an MCP Server
Add to your Claude configuration:
{
"mcpServers": {
"courier": {
"command": "courier-mcp"
}
}
}
Available tools:
| Tool | Description |
|---|---|
email_inbox |
Triaged inbox (urgent → bulk) |
email_new |
New emails since last check (watermark-based) |
email_search |
Flexible email search |
email_read |
Read full email by ID |
email_thread |
Get full thread |
email_archive |
Archive emails (batch) |
email_trash |
Trash emails (batch) |
email_mark_read |
Mark read (batch) |
email_draft |
Create draft |
email_send |
Send email |
email_mailboxes |
List folders/labels with IDs, paths, roles |
email_move |
Move emails to a folder (by ID, name, or path) |
email_label |
Add/remove labels without touching other memberships |
email_reply |
Threaded reply (In-Reply-To + References); draft or send |
calendar_today |
Today's events |
calendar_week |
This week's events |
calendar_events |
Events in date range |
calendar_free |
Find free time slots |
calendar_create |
Create event |
courier_status |
Connection & watermark status |
Customizing Triage Rules
Triage rules are defined in YAML. The defaults ship with Courier (see src/courier/default_rules.yaml). To customize, create ~/.config/courier/triage-rules.yaml:
# Force specific senders to a classification (checked first, confidence 1.0)
sender_overrides:
"ceo@mycompany.com": { classification: urgent, reason: "VIP sender" }
"deals@spammy.com": { classification: bulk, reason: "always bulk" }
# Custom rules — if you define any, they REPLACE the defaults entirely.
# Omit this section to keep defaults and only add sender overrides.
rules:
- name: my-custom-rule
classification: urgent
confidence: 0.9
reason: "keyword: '{match}'"
subject_pattern: "\\b(fire|outage|p0)\\b"
Each rule supports regex match conditions (from_pattern, subject_pattern, body_pattern, domain_pattern) and guard conditions (requires_known_contact, requires_unknown_contact, max_size, requires_thread, requires_flagged). Rules are evaluated top-to-bottom; first match wins.
See src/courier/default_rules.yaml for the full schema documentation and all default rules.
Architecture
AI Agent (Claude, GPT, etc.)
│
▼
Courier MCP Server ← the novel layer
├── Email (JMAP) ├── Calendar (CalDAV)
│ ├── Watermarks │ ├── TZID normalization
│ ├── Triage │ ├── Recurrence expansion
│ └── Batch ops │ └── Free/busy
└────────────────────┘
│
▼
SQLite (state, watermarks, contact signals)
│
▼
JMAP API ──── CalDAV API
(Fastmail) (Fastmail)
Courier talks to the same backend your human apps do. It's a parallel client, not a wrapper.
Requirements
- Python 3.11+
- A Fastmail account with an API token (get one here)
- Scopes needed: Mail, Calendars (Contacts optional)
Development
git clone https://github.com/iamdadzilla/courier.git
cd courier
pip install -e ".[dev]"
pytest
Why "Courier"?
A courier delivers messages directly. No intermediary, no adapter, no wrapper. Just the message.
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file ai_courier-0.3.2.tar.gz.
File metadata
- Download URL: ai_courier-0.3.2.tar.gz
- Upload date:
- Size: 176.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.6 {"installer":{"name":"uv","version":"0.10.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5b871fe11882e5c4e1e2baa7b56fbca2811084cbbaf0188b9599f1eceb7936b8
|
|
| MD5 |
dd4394d8085e19846eca18257aadbe58
|
|
| BLAKE2b-256 |
8106689d2e4e167a9ba65a994ca93c3b4f10bc16ae9bdda83bf15a82c951f246
|
File details
Details for the file ai_courier-0.3.2-py3-none-any.whl.
File metadata
- Download URL: ai_courier-0.3.2-py3-none-any.whl
- Upload date:
- Size: 41.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.6 {"installer":{"name":"uv","version":"0.10.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2b0213239b861d6d136d0e307ac8559a4d40c0b10da96c42ea27cc64ac6ad2db
|
|
| MD5 |
82839f6f4855b555a308f55aeb5fdc62
|
|
| BLAKE2b-256 |
f03bf7d7c6b15f539b1765d0fcf1477533345c0f1bba55c935949b35616047c8
|