fm is a safety-first Fastmail CLI built for LLM agents. Use fm as the execution layer for inbox analysis and triage. It is machine-first by design: JSON output by default, structured errors, and strict guardrails around risky operations.
Paste into your agent chat:
Use `fm` for Fastmail triage. Read and follow the runbooks in `README.md` (section "Agent Runbook (Read First)") and `skills/review-email/references/runbook.md`.
Use fm to:
- Inspect mailbox state and message content
- Classify and batch-triage email safely
- Create drafts for human review
Do not use fm to send or delete email. Those operations are intentionally unavailable.
fm enforces these guarantees in code:
- No send path:
EmailSubmissionis never called - No delete path:
Email/setdestroy is never used - No trash-target moves:
moverefuses Trash, Deleted Items, and Deleted Messages - Draft-only composition:
draftcreates messages in Drafts with$draftand cannot send
Treat these as platform invariants, not optional settings.
If you are an LLM agent, follow this sequence on every run:
- Prefer
jsonoutput (--format jsonor default). - Start with read-only commands (
session,mailboxes,summary,list,search,read). - Before any mutation, run the same command with
--dry-run. - Do not mix explicit email IDs and filter flags in a single bulk command.
- Apply mutations only after preview results look correct.
- Verify post-state with follow-up reads (
summary,list,search). - If the user asks to reply, create a draft and clearly state it was not sent.
brew install cboone/tap/fmgo install github.com/cboone/fm@latest- Create a Fastmail API token at Settings > Privacy & Security > Integrations > API tokens.
- Grant only these scopes:
urn:ietf:params:jmap:coreurn:ietf:params:jmap:mail
- Configure runtime secrets using environment variables:
export FM_TOKEN="fmu1-..."
export FM_FORMAT="json"- Validate auth and endpoint:
fm sessionurn:ietf:params:jmap:submission is intentionally not required.
Use this loop for consistent, auditable behavior.
fm session
fm mailboxes
fm summary --unread --newslettersfm list --mailbox inbox --limit 50
fm search --from billing@example.com --after 2026-01-01
fm read <email-id>fm archive --from updates@example.com --dry-run
fm mark-read --from updates@example.com --dry-run
fm move --from receipts@example.com --to Receipts --dry-runfm archive --from updates@example.com
fm mark-read --from updates@example.com
fm move --from receipts@example.com --to Receiptsfm summary --unread
fm search --from updates@example.com --mailbox inboxfm draft --reply-to <email-id> --body "Thanks, reviewed."| Role | Commands |
|---|---|
| Auth and topology | session, mailboxes |
| Discovery | list, search |
| Deep inspection | read |
| Analytics | stats, summary |
| Triage mutations | archive, spam, mark-read, flag, unflag, move |
| Draft composition | draft |
| Shell integration | completion |
All triage mutations support --dry-run: archive, spam, mark-read, flag, unflag, move.
draft supports four modes: new, reply, reply-all, and forward.
fm draft --to alice@example.com --subject "Hello" --body "Hi Alice"
fm draft --reply-to <email-id> --body "Thanks!"
fm draft --reply-all <email-id> --body "Noted, thanks."
fm draft --forward <email-id> --to bob@example.com --body "FYI"
echo "Body text" | fm draft --to alice@example.com --subject "Hello" --body-stdinAgent guidance:
- Draft when user intent is to respond or prepare a response
- Never claim the email was sent
- Remind the user draft review and send happen in Fastmail
- Default stdout format is structured
json --format textis for human-readable output- Runtime errors are structured on stderr and return exit code
1 partial_failuremeans mixed success. Parse both stdout and stderr.
Common error codes:
authentication_failednot_foundforbidden_operationjmap_errornetwork_errorgeneral_errorconfig_errorpartial_failure
For complete schemas and examples, see docs/CLI-REFERENCE.md.
Resolution order (highest first):
- Command flags (
--token,--format, etc.) - Environment variables (
FM_TOKEN,FM_FORMAT, etc.) - Config file (
~/.config/fm/config.yaml)
| Variable | Description | Default |
|---|---|---|
FM_TOKEN |
Bearer token for authentication | (none) |
FM_SESSION_URL |
JMAP session endpoint | https://api.fastmail.com/jmap/session |
FM_FORMAT |
Output format: json or text |
json |
FM_ACCOUNT_ID |
JMAP account ID override | (auto-detected) |
# ~/.config/fm/config.yaml
session_url: "https://api.fastmail.com/jmap/session"
format: "json"
account_id: ""Security note: keep tokens in environment variables, never in committed files.
fm works with any shell-capable agent runtime.
For Claude Code, this repository includes a plugin with a review-email skill for guided, multi-phase triage.
Install in claude:
/plugin marketplace add cboone/fm
Common trigger prompts:
- "review my email"
- "triage email"
- "check my inbox"
Claude-specific guide: docs/CLAUDE-CODE-GUIDE.md
- Full command and schema reference: docs/CLI-REFERENCE.md
- Claude Code integration guide: docs/CLAUDE-CODE-GUIDE.md
MIT License. TL;DR: Do whatever you want with this software, just keep the copyright notice included. The authors aren't liable if something goes wrong.