Send emails with the CLI
Install the postshiba command, sign in, and send from your terminal.
What you'll build
A receipt email sent from your terminal with postshiba, then a few account commands you can reuse in scripts.
Before you start
- An API key with Full access. See Create an API key. Support keys cannot send.
- A verified sending domain. See Add and verify a domain.
frommust be an address on it. - A cluster that is ready to send (
sending_readyistrue). See Clusters. - Your team id. It is on the API keys page.
- Node.js 20 or later.
Install
For a one-off run without installing:
On a terminal, postshiba with no arguments opens a menu: send an email, add a sending domain, inspect clusters and inboxes, check your setup, or install the agent skill. Missing fields become prompts, with a spinner and a table for the result.
Sign in
Run postshiba login. It asks for the API key, checks it, then prints Signed in as your email. It then asks for your team id, and offers a default cluster if you have one. The key is never printed.
Or set environment variables and skip the config file:
Each invocation reads a flag first, then the matching env var, then ~/.config/postshiba/config.json. A missing key is a usage error that names postshiba login and POSTSHIBA_API_KEY. A team-scoped command without a team id names --team. postshiba whoami reprints the signed-in user. postshiba logout deletes the config file.
Send your first email
On a terminal, postshiba send prompts for anything missing. from suggests hello@ on a verified domain. to is comma-separated. Then pick a body: plain text, an HTML file, or a published template. Confirm the preview, and the success line includes the message id.
To skip the prompts, pass the flags:
The message then shows under Events in the dashboard. from and at least one --to are required. Repeat --to for more recipients. Pass --cluster NmQpXr to pin a cluster. Without it, the CLI uses the default from login or POSTSHIBA_CLUSTER_ID, or lets the API pick a sending-ready cluster.
With --json, success prints the API body:
Templates and sandbox tests
Pass --template with the alias or public id and --var key=value for each Liquid variable. Leave out --text and --html.
--sandbox runs every send check without delivering. It requires --cluster and posts to the cluster send path.
--idempotency-key also uses that cluster path. See Sending.
Manage your account from the terminal
Commands follow postshiba <resource> <action>. Positional ids follow the path. Rows that create or update take --data as JSON, @file.json, or - for stdin.
| Resource | Example |
|---|---|
clusters |
postshiba clusters get NmQpXr |
sending-domains |
postshiba sending-domains create --data '{"name":"mail.example.com"}' |
messages |
postshiba messages get PqRzMn GxTyVu |
events |
postshiba events list NmQpXr |
smtp-credentials |
postshiba smtp-credentials create NmQpXr --data @cred.json |
firewall |
postshiba firewall add-entry --data @entry.json |
Also network, tenants, inboxes, webhooks, templates, and suppressions. postshiba sending-domains make-primary HsVtYk promotes a domain. postshiba messages download-attachment PqRzMn GxTyVu 1 --output photo.png writes the file. postshiba help clusters lists the actions for a resource.
doctor checks that the key is valid, a team id is set, a cluster is sending_ready, and a sending domain is verified. Each failure prints the command that fixes it.
Scripts and agents
Interactive mode needs a TTY, no --json, and CI unset. Otherwise the CLI is plain: no prompts, and a successful call prints the API JSON with 2-space indent. --no-input forces that. A missing flag is then a usage error.
| Flag | Effect |
|---|---|
--json |
Print API JSON. Never prompt. |
--no-input |
Never prompt. Missing input exits 2. |
--yes |
Skip the confirm on delete, suspend, release, and unassign. Plain mode requires it for those actions. |
| Exit | Meaning |
|---|---|
0 |
Success. |
1 |
The API returned an error. |
2 |
Usage error: unknown command, missing id, missing --data, or bad JSON. The message points at postshiba help <resource>. |
The CLI ships an agent skill that teaches an assistant to pass --json, read credentials from the environment, run doctor --json first, and use --sandbox for tests. --yes only when you asked for a destructive action.
That writes .cursor/skills/postshiba-cli/ in this project. Pass --global to install under your home directory, or --target claude or --target agents for those layouts. You can also run npx skills add postshiba/postshiba-cli. The same skill is in the PostShiba Cursor plugin.
Troubleshooting
A non-2xx response prints Error: <message> on stderr and, when present, (field: <field>). Then the process exits 1.
| Status | error |
What the CLI does |
|---|---|---|
401 |
Invalid token or no user signed in |
Prints the error. The API key is missing, mistyped, or deleted. Copy it again from API keys, or run postshiba login. |
403 |
forbidden, domain_unverified, or kyc_required |
Prints the error. Use a Full access key and a verified from. While your team is pending production approval, send only to team members, live inbox addresses, and inbox forward-to addresses. |
422 |
invalid |
Prints the error and field when the API names one, such as a missing to, an unpublished template, or a rejected attachment. |
429 |
throttled |
Prints the error, then The cluster hit its hourly send limit. Wait until the next hour before retrying. Do not retry in that window. See What happens at your cap. |
Every other status is on Errors.
Next steps
- Choose a send path if you need SMTP or HTTP inject for volume.
- Unique args to get your own ids back on delivery webhooks.
- Connect MCP to query PostShiba from Cursor.
- SDKs for every language client.