Email CLI
Send, receive, and manage email from your terminal. Built for AI agents.
A single binary that gives your AI agent a real email address. Send, receive, reply, draft, sync, and manage contacts through Resend -- all from the command line. No IMAP. No browser inbox. No MCP server. Just a local SQLite mailbox and 50+ commands.
Why This Exists | Install | How It Works | Commands | Configuration | Contributing
Why This Exists
AI agents need to send and receive email. The existing options are bad:
- IMAP/SMTP requires complex server configuration, credential management, and connection handling. Agents struggle with it.
- Email APIs work for sending, but agents need a local mailbox to track threads, drafts, and read status.
- Browser-based inboxes are not scriptable. Agents cannot use them.
Email CLI solves this by wrapping the Resend API in a local-first CLI. Your agent gets a verified email address, a local SQLite mailbox, and structured JSON output with semantic exit codes. It calls agent-info once to learn every command, then works from memory.
You can also use it as a human. It works the same way.
Install
Homebrew (macOS/Linux)
Cargo (any platform)
From source
# binary: ./target/release/email-cli
Quick Start
# 1. Add your Resend API key
# 2. Verify domain connectivity
# 3. Register a sending identity
# 4. Send an email
# 5. Sync and read incoming mail
# 6. Reply (threads correctly with In-Reply-To + References)
# 7. Reply All (preserves CC recipients)
# 8. Forward
# 9. Thread a new send into an existing conversation
How It Works
Three concepts:
- Profile -- a Resend API key. You can have multiple profiles for different Resend accounts.
- Account -- a sender/receiver identity (
agent@yourdomain.com). Each account belongs to a profile. - Local mailbox -- a SQLite database that stores messages, drafts, attachments, and sync cursors.
Resend handles delivery. Email CLI handles the local operating model that agents need: read tracking, threading, drafts, batch sends, and structured output.
┌────────────────────────────────┐
│ Your Agent / You │
│ (Claude, Codex, Gemini) │
└──────────────┬─────────────────┘
│ CLI commands
▼
┌────────────────────────────────┐
│ email-cli │
│ 50+ commands, JSON output, │
│ semantic exit codes │
└──────────┬─────────┬───────────┘
│ │
┌─────▼──┐ ┌───▼────────┐
│ SQLite │ │ Resend API │
│ local │ │ (send, │
│ store │ │ receive, │
│ │ │ domains) │
└────────┘ └────────────┘
Commands
Core Email
| Command | What it does |
|---|---|
send |
Send email (--reply-to-msg for threading, --cc, --bcc, --attach) |
reply <id> |
Reply with proper threading headers (--all for Reply All) |
forward <id> |
Forward a message (--to, --cc, --text for preamble) |
sync |
Pull sent and received messages into local store |
inbox ls |
List messages (filter by account, unread status) |
inbox read <id> |
Read a message, optionally mark as read |
inbox search <q> |
Search messages by keyword |
inbox delete <id> |
Delete a message |
inbox archive <id> |
Archive a message |
draft create |
Save a local draft with attachment snapshots |
draft list |
List all drafts |
draft show <id> |
View draft details |
draft edit <id> |
Edit a draft |
draft send <id> |
Send a draft and delete it |
draft delete <id> |
Delete a draft |
attachments list <id> |
List attachments on a message |
attachments get <id> <att> |
Download an attachment to disk |
Account Management
| Command | What it does |
|---|---|
profile add <name> |
Add or update a Resend API profile |
profile list |
List all profiles |
profile test <name> |
Test API connectivity |
account add <email> |
Register an email identity |
account list |
List all accounts |
account use <email> |
Set the default sending account |
signature set <account> |
Set per-account signature |
signature show <account> |
Show signature |
Resend Management
| Command | What it does |
|---|---|
domain list |
List your Resend domains |
domain get <id> |
Get domain details with DNS records |
domain create --name <d> |
Register a new domain |
domain verify <id> |
Trigger domain verification |
domain delete <id> |
Delete a domain |
domain update <id> |
Update tracking settings |
audience list |
List audiences |
audience create --name <n> |
Create an audience |
audience delete <id> |
Delete an audience |
contact list --audience <id> |
List contacts in an audience |
contact create |
Create a contact |
contact update |
Update a contact |
contact delete |
Delete a contact |
batch send --file <path> |
Send batch emails from a JSON file |
api-key list |
List API keys |
api-key create --name <n> |
Create an API key |
api-key delete <id> |
Delete an API key |
Agent Tooling
| Command | What it does |
|---|---|
agent-info |
Machine-readable JSON capability manifest |
skill install |
Install skill file for Claude/Codex/Gemini |
skill status |
Check skill installation status |
completions <shell> |
Generate shell completions (bash/zsh/fish) |
Email Threading
Every outgoing email gets a unique Message-ID header (<uuid@yourdomain.com>). Replies set In-Reply-To and References per RFC 5322, so threads display correctly in Gmail, Outlook, and Apple Mail.
| Action | Headers Set | Threading |
|---|---|---|
send |
Message-ID | New conversation |
send --reply-to-msg <id> |
Message-ID, In-Reply-To, References | Threads into existing conversation |
reply <id> |
Message-ID, In-Reply-To, References | Threads into existing conversation |
reply <id> --all |
Same + preserves CC | Threads with all recipients |
forward <id> |
Message-ID only | New conversation (per RFC) |
Agent Integration
Email CLI follows the agent-cli-framework patterns. Any agent that speaks structured JSON can use it.
Capability Discovery
Returns a JSON manifest of every command, flag, exit code, and output format. An agent calls this once and works from memory.
Structured Output
All commands produce JSON when piped or when you pass --json:
Errors include actionable suggestions:
Semantic Exit Codes
| Code | Meaning | Agent action |
|---|---|---|
| 0 | Success | Continue |
| 1 | Transient error (network) | Retry |
| 2 | Configuration error | Fix setup |
| 3 | Bad input | Fix arguments |
| 4 | Rate limited | Wait and retry |
Skill Self-Install
Writes a skill file to ~/.claude/skills/email-cli/, ~/.codex/skills/email-cli/, and ~/.gemini/skills/email-cli/. The skill tells agents the CLI exists and to run agent-info for full details.
Configuration
Local State
All data lives in ~/.local/share/email-cli/email-cli.db (override with --db <path>). Sibling directories:
draft-attachments/-- snapshots of files attached to draftsdownloads/-- fetched attachments (configurable via--output)
Database Tables
| Table | Purpose |
|---|---|
profiles |
API key storage |
accounts |
Email identities with signatures |
messages |
Sent and received email with full metadata |
drafts |
Local drafts with attachment snapshots |
attachments |
Attachment metadata and local file paths |
sync_state |
Per-account sync cursor positions |
SQLite runs with WAL mode, busy timeout, and foreign keys enabled.
Security
- API keys live in the local SQLite database. Treat
email-cli.dbas sensitive. - Use
--api-key-env VAR_NAMEor--api-key-file pathinstead of passing keys directly. - Attachment filenames are sanitized before writing to disk.
- Each send includes a UUID
Idempotency-Keyheader.
Requirements
- A Resend API key with sending enabled
- A verified Resend domain (enable receiving on the domain for inbox sync)
- Rust 1.85+ if building from source (edition 2024)
Contributing
Contributions are welcome. See CONTRIBUTING.md for guidelines.
License
MIT -- see LICENSE.
Built by Boris Djordjevic at 199 Biotechnologies | Paperfoot AI
If this is useful to you: