@openmail/cli is how agents that live in a shell talk to OpenMail: Claude Code, Cursor, Codex, or a cron job. On OpenClaw the plugin bundles it, so nothing on this page needs installing there.
Install
Needs Node 20 or newer.init creates an inbox, stores it as the default, and saves the key you gave it to ~/.openmail-cli/state.json (mode 600). Every command that takes --inbox-id falls back to that default.
Authentication
Key resolution, first match wins:--api-key, OPENMAIL_API_KEY (environment or a .env in the working directory), then the key init saved.
In CI or anywhere commands get logged, use the environment variable. --api-key shows up in process lists and shell history.
Key scope decides what works:
Commands
openmail help <command> prints the full flag list for any group. What follows is one working example per thing you’d do.
Send
--to, on purpose: the CLI refuses a second so an agent can’t spray. Repeat --cc for the others. HTML in --body is detected. With --thread-id the subject is optional and the API quotes the previous message under your text the way a mail client does; --no-quote sends your text alone, handy when the chain is long. --reply-to on the free plan has to be an inbox you own; --idempotency-key makes retries safe.
Read
threads list --is-read false, handle what comes back, mark each thread read.
Attachments
text returns extracted text for PDF, DOCX, XLSX, PPTX, and images (OCR), so the agent reads the document without parsing it. get downloads the raw file. Ids and filenames come from threads get.
Inboxes
--domain needs a verified custom domain. A pod-scoped key always creates in its own pod; account keys pass --pod-id.
Inbox keys and webhooks live here too:
threads list --is-read false does it without one.
Pods
--client-id is your own id for the pod and works anywhere a pod_id does. Pod management needs an account key. See Pods.
Domains
--pod-id on add ties the domain to one pod; leave it off for account-wide.
Policy
--pod-id or --inbox-id narrows it. Modes are none, allowlist, and inherit; an empty allowlist denies everyone. Inbox keys can’t touch policy. See Sender rules.
Feedback
bug, friction, feature_request.
Global flags
Environment variables
Read from the environment first, then a
.env in the working directory. The matching flag wins over both.
Exit codes
0 on success, 1 on anything else: bad flags, missing key, API errors. With --json the error is a JSON object on stderr, so scripts can branch on the code and parse the reason.
Updating
update runs npm install -g for you; upgrade is an alias.
Limits
- One page per list call.
--limitand--offsetonly. Nothing auto-paginates. - No confirmation on delete or revoke.
inbox deleteandkeys revokerun as soon as you press enter, which is what an agent wants and what a typo doesn’t.
Source and support
The CLI is open source at openmailsh/cli; bugs and feature requests go in its issues, or straight from the terminal withopenmail feedback.
Related
- OpenClaw: the plugin that bundles this CLI
- Claude Code: the skill that teaches it these commands
- API reference: what each command calls