CLI
The Postilon CLI sends email and manages domains, received email, webhooks, templates, suppressions and API keys from your terminal. It needs Node.js 18.3 or later.
npm install -g @postilon/cli
To run it once without installing, use npx @postilon/cli in place of postilon. The source is at github.com/postilon/postilon-cli (MIT).
Sign in
postilon login
Paste an API key from the dashboard (API Keys). The CLI checks the key with the API and saves it to ~/.config/postilon/config.json ($XDG_CONFIG_HOME/postilon/config.json when that is set), where only you can read it. To skip the prompt, pipe the key in: echo "$KEY" | postilon login.
In CI and scripts, set POSTILON_API_KEY instead. It takes precedence over the saved key. postilon whoami shows which key is in use and where it came from, and postilon logout deletes the saved key.
Start with a ps_test_… key. Emails sent with it are accepted and reported like real ones, but nothing is delivered and no credits are used.
Send an email
postilon send \
--from "Acme <hello@acme.com>" \
--to jane@example.com \
--subject "Your sign-in code" \
--text "Your code is 482913."
The CLI prints the email's ID, such as Queued msg_4kQ9wZ2xT7bLmN3pR8sV to jane@example.com (test).. Follow the email with postilon emails get msg_….
| Option | Description |
|---|---|
-f, --from |
Sender: hello@acme.com or Acme <hello@acme.com>. Required. |
-t, --to |
Recipient. Required. Repeat the option or separate addresses with commas. |
--cc, --bcc |
Copy recipients, the same way. |
-s, --subject |
Subject. Required unless you use --template. |
--text, --html |
The body. |
--text-file, --html-file |
The body from a file; - reads standard input. |
--reply-to |
Reply-To address. |
--template, --var name=value |
Render a template (tmpl_…) with its variables. Repeat --var for each variable. |
--tag name=value |
Add a tag. Repeat for more tags. |
--header "Name: value" |
Add an extra header. Repeat for more headers. |
--attach path |
Attach a file. Repeat for more files. |
--schedule |
Send at an RFC 3339 time, such as 2026-11-01T09:00:00Z. |
--idempotency-key |
Send at most once for this key. See Idempotency. |
# An HTML file, an attachment and a tag
postilon send -f billing@acme.com -t jane@example.com -s "Receipt" \
--html-file receipt.html --attach invoice.pdf --tag category=receipt
# A template
postilon send -f hello@acme.com -t jane@example.com --template tmpl_welcome --var name=Jane
Commands
| Command | Description |
|---|---|
postilon emails list |
List sent emails. Filter with --status, --search, --source (api or smtp) and --days. |
postilon emails get <id> |
Show an email and its events. |
postilon emails cancel <id> |
Cancel a queued or scheduled email. |
postilon domains list |
List domains. |
postilon domains add <name> |
Add a domain and print the DNS records it needs. |
postilon domains verify <domain> |
Check the domain's DNS records now. |
postilon domains get <domain> |
Show a domain and its DNS records. |
postilon domains update <domain> |
Change --open-tracking or --click-tracking (on or off), or the --inbound-domain ("" turns inbound off). |
postilon domains remove <domain> |
Remove a domain. |
postilon inbound list |
List received email. Search with --search. |
postilon inbound get <id> |
Show a received email, its authentication results and its attachments. |
postilon inbound raw <id> |
Print the message as received, or save it with -o message.eml. |
postilon inbound attachment <id> <index> |
Save an attachment (index counts from 0) under its own name, or under the name you give with -o. |
postilon webhooks list, get <id> |
List or show webhook endpoints. |
postilon webhooks add <url> |
Add an endpoint for --events (every event if you leave it out) and print its signing secret. |
postilon webhooks update <id> |
Change --url, --description or --events, or --enable or --disable the endpoint. |
postilon webhooks remove <id> |
Remove an endpoint. |
postilon webhooks test <id> |
Send a webhook.test event. |
postilon webhooks events |
List the event types. |
postilon webhooks deliveries |
List recent deliveries, or one endpoint's with --webhook <id>. |
postilon webhooks replay <delivery-id> |
Send a delivery again. |
postilon templates list, get <id> |
List or show templates. |
postilon templates create <name> |
Create a template with --subject, --html/--html-file and --text/--text-file. |
postilon templates update <id> |
Change a template's --name or content. |
postilon templates remove <id> |
Delete a template. |
postilon suppressions list |
List suppressed addresses. |
postilon suppressions add <address> |
Stop sending to an address. |
postilon suppressions remove <address> |
Allow sending to the address again. |
postilon api-keys list |
List API keys, without their secrets. |
postilon api-keys create <name> |
Create a key with --environment (live or test), --scope (full_access or sending_access), --domain and --expires-in-days. The key is shown only once. |
postilon api-keys revoke <id>, remove <id> |
Revoke or delete a key. |
postilon credits |
Show the credit balance and the next expiry. |
A <domain> is a name such as acme.com or an ID (dom_…). A suppression can also be removed by its ID (sup_…). Lists show 100 items per page; use --limit and --offset to page through them. Everything except send and emails needs a full-access key.
Run postilon --help, postilon <command> --help or postilon <command> <subcommand> --help for every option.
Scripts and CI
Add --json to any command to print the API's response as JSON instead of a table:
postilon emails list --status bounced --days 1 --json | jq -r '.data[].to[]'
The CLI exits with 0 on success, 1 when the API returns an error or cannot be reached, and 2 when the command line is wrong. Errors go to standard error with the API's error code, such as Error: Sender domain acme.com is not verified in this workspace. … (domain_not_verified, HTTP 403).
Set POSTILON_API_URL to use another API, such as a local server at http://localhost:8080.