Skip to content

CLI

Set up, inspect, replay, and diagnose OutSend from a shell script, a runbook, or a CI job.

Everything you can do by clicking, available to a script. The CLI is the same API underneath, so anything it can do an agent or a cron job can do too.

Install

npm install -g @outsend/cli
# or
brew install outsend

Authenticate

outsend auth login            # prompts for an API key, stores it in your keychain
outsend auth status           # shows which workspace and scope the key has

Prefer an environment variable in CI:

export OUTSEND_API_KEY="..."

Domain-scoped keys work here too. If a command needs broader scope than your key has, the error says which scope is missing rather than returning a bare 403.

Send

outsend send \
  --from alerts@yourdomain.com \
  --to person@example.com \
  --subject "Reset your password" \
  --html "<p>Here is your link.</p>" \
  --idempotency-key password-reset-8f21c4

Pipe a body in instead of quoting it:

cat reset.html | outsend send --from alerts@yourdomain.com --to person@example.com \
  --subject "Reset your password" --html -

Inspect

This is the part worth learning. trace prints the full lifecycle of a message, including the receiving provider’s own response on every event:

outsend trace 10482
message 10482  person@example.com

09:14:02.114  queued          accepted · idempotency-key password-reset-8f21c4
09:14:02.380  sent            handed to AWS SES · us-east-1
09:14:03.921  delivery_delay  450 4.7.1 Not accepted, try again later
09:16:41.552  delivery        250 2.0.0 OK — accepted after retry

reputation  isolated sender · unaffected by the deferral

Query the event log:

outsend events list --type bounce --since 24h
outsend events list --recipient person@example.com
outsend events tail --type delivery_delay        # follow live
outsend events list --since 1h --json | jq '.[] | .provider.response'

Every command takes --json, so the CLI composes with jq and with anything else that reads a pipe.

Explain

explain takes a set of failures and tells you what they have in common — provider concentration, the signal behind it, and what the evidence supports:

outsend explain --since 09:00 --status failed
matched:               17 messages
provider concentration: Outlook
signal:                temporary reputation deferral
evidence:              event trace + provider response
recommended action:    slow route, verify DKIM alignment
approval required:     apply routing change

It stops at the recommendation. Consequential changes need outsend apply <plan-id> and a human to run it.

Domains

outsend domains list
outsend domains add yourdomain.com --region us-east-1
outsend domains records yourdomain.com          # the DNS records to publish
outsend domains verify yourdomain.com

records prints in a form you can paste, or --json for a Terraform or Pulumi pipeline.

Keys, suppressions, contacts

outsend keys list
outsend keys create --name ci --domain yourdomain.com
outsend keys revoke key_8f21c4

outsend suppressions list --stream broadcast
outsend suppressions remove person@example.com --stream broadcast

outsend contacts import contacts.csv
outsend contacts export --segment "active-customers" > out.csv

Webhooks

outsend webhooks list
outsend webhooks test https://your-app.com/hooks --event email.bounced
outsend webhooks deliveries --webhook wh_2f10 --failed

deliveries shows attempts, response codes, and response bodies — the same delivery log the dashboard shows.

Migrating

outsend migrate suppressions --from sendgrid --file suppressions.csv
outsend migrate check --from postmark

migrate check reads your current configuration and reports what will need to change: field names, webhook shape, DNS records, and which suppression lists have not been imported yet.

Diagnostics

outsend doctor

Checks the things that actually break sending: DNS records and their propagation, whether SPF is duplicated, key scope, reputation state, webhook endpoint health, and clock skew. It reports what it checked and what it could not check, rather than a green tick.