Mailhub
Mailhub is a local, MCP-first personal-operations hub for AI assistants and their humans.
Features
- Mail — Gmail, Microsoft Graph (Outlook.com), IMAP/SMTP
- Calendar — Google Calendar, Microsoft Graph, CalDAV
- Contacts — Google People, Microsoft Graph, CardDAV
- Tasks — Microsoft To Do (Graph), CalDAV VTODO
- MCP-first — stdio MCP server for AI agents (read-only + full modes)
- REST API — localhost-only HTTP server for scripts/CLI
- CLI —
mailhub(admin) andmail(user) commands
Quick Start
# Install
uv tool install --editable .
# Initialize config & state
mailhub init
# Configure OAuth clients (one-time)
mailhub config setup-google # Opens Google Cloud Console, guides OAuth setup
mailhub config setup-microsoft # Opens Entra ID, guides app registration
# Add accounts
mailhub config add-account --alias me --provider gmail --capabilities mail --email me@gmail.com
mailhub config add-account --alias work --provider graph --capabilities mail --email me@outlook.com
# Authorize accounts (opens browser, paste redirect URL)
mailhub auth gmail me --code '<pasted-redirect-url>'
mailhub auth graph work --code '<pasted-redirect-url>'
# Verify health
mailhub doctor
# Start REST server (localhost only)
mailhub serve
# Or run MCP server (read-only by default)
mailhub mcp --mode ro
# Or full mode for mutations
mailhub mcp --mode full
Using the mail CLI
The mail command is a thin HTTP client to the REST API (requires mailhub serve running):
# List accounts
mail accounts
# List folders
mail folders me
# Search messages
mail search me "from:github.com newer_than:7d"
mail search work "hasAttachments:true"
# Get message
mail get me <message-id>
# Send (requires --confirm)
mail send me --to someone@example.com --subject "Hello" --body "Test" --confirm
# Create draft
mail draft me --to someone@example.com --subject "Draft" --body "Content"
Systemd Service (Auto-start)
# Install service files
mkdir -p ~/.config/systemd/user
cp deploy/*.service deploy/*.timer ~/.config/systemd/user/
# Enable and start
systemctl --user daemon-reload
systemctl --user enable --now mailhub.service mailhub-doctor.timer
loginctl enable-linger # keeps user services alive after logout
Configuration
Config lives at ~/.config/mailhub/config.toml:
[server]
host = "127.0.0.1"
port = 8787
[auth]
ro_token = "..." # read-only token
full_token = "..." # full-access token
[send]
allowlist = ["*@example.com"] # glob patterns
# allow_anywhere = true # disable allowlist
[gmail]
client_id = "..."
client_secret = "..."
[graph]
client_id = "..."
[accounts.personal]
provider = "gmail"
capabilities = ["mail", "calendar", "contacts"]
[accounts.work]
provider = "graph"
capabilities = ["mail", "calendar", "contacts", "tasks"]
Security
- REST server binds only to 127.0.0.1 (never 0.0.0.0)
- No hard-delete — only trash/cancel
- Mutations require
confirm=true+ recipient allowlist - Audit log (
~/.local/state/mailhub/audit.jsonl) never records tokens/bodies - Credentials stored with 0600 permissions, atomic writes, fcntl lock
- OAuth PKCE with random state
- Message bodies treated as untrusted input
Development
uv sync --extra dev
uv run pytest
uv run mailhub init
uv run mailhub status
uv run mailhub mcp --mode ro
Architecture
mailhub/
├── config.py # TOML config, validation, provider capabilities
├── store.py # Credential store (atomic, 0600, fcntl lock)
├── oauth.py # PKCE OAuth for Google/Microsoft
├── core.py # Policy engine, allowlist, audit, retry, adapters
├── util.py # HTML→text, MIME, address parsing
├── gmail.py # Gmail API adapter
├── graph.py # Microsoft Graph adapter
├── gcal.py # Google Calendar adapter
├── gcal_graph.py # Graph Calendar adapter
├── caldav.py # CalDAV adapter (read)
├── people.py # Google People adapter
├── people_graph.py # Graph People adapter
├── carddav.py # CardDAV adapter (read)
├── tasks.py # Tasks domain
├── tasks_graph.py # Graph Tasks adapter
├── tasks_caldav.py # CalDAV VTODO adapter (read)
├── app.py # FastAPI REST server (127.0.0.1 only)
├── cli.py # mailhub admin CLI
├── mail_cli.py # mail user CLI (thin REST client)
├── mcp.py # MCP server (ro + full modes)
├── backup.py # Backup/restore utilities
└── deploy/ # systemd user units
License
MIT
Man Pages
Install man pages system-wide:
sudo cp docs/man/mailhub.1 /usr/local/share/man/man1/
sudo cp docs/man/mail.1 /usr/local/share/man/man1/
sudo mandb
Then view with:
man mailhub
man mail
Or view locally without installing:
man -l docs/man/mailhub.1
man -l docs/man/mail.1
Shell Completions
Generate completion scripts for your shell:
mailhub --generate-completion bash > ~/.local/share/bash-completion/completions/mailhub
mailhub --generate-completion zsh > ${fpath[1]}/_mailhub
mailhub --generate-completion fish > ~/.config/fish/completions/mailhub.fish
The completion script also covers the mail command (same stub).
Metadata
Release files for zc-mailhub 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| zc_mailhub-0.1.0.tar.gz | 213.9 kB | With provenance | Details for zc_mailhub-0.1.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| zc_mailhub-0.1.0-py3-none-any.whl | Python 3 | none | any | Details for zc_mailhub-0.1.0-py3-none-any.whl |
Total release size: 274.9 kB
Release files / zc_mailhub-0.1.0.tar.gz
| Download URL | zc_mailhub-0.1.0.tar.gz |
|---|---|
| Size | 213.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
ab95ea5a43bafad33d1e29a4c7bba05a9e796ea8255e741cbc25d2f2738d9562
|
|
BLAKE2b-256 checksum How to use checksums |
98a1f119bee938937f7b0f7ddaf64114f4e4e9106108a64382d2f008757fe5d4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 23, 2026.
Transparency logRelease files / zc_mailhub-0.1.0-py3-none-any.whl
| Download URL | zc_mailhub-0.1.0-py3-none-any.whl |
|---|---|
| Size | 61.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
0a68af2d68312fc52edd26baaedff86f4786c6396b37dfde6da4ed4102d49806
|
|
BLAKE2b-256 checksum How to use checksums |
26aa866b89079566ecadd2381492cb3f93d3cf9a27f7d4c98a762d8ee0e5e7ac
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 23, 2026.
Transparency logSecurity for zc-mailhub 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for zc_mailhub-0.1.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 23, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.