CodeOutbox docs
Email marketing that lives in your codebase: paste a form, write newsletters in Markdown, and send from the CLI, the API, or your coding agent. We run our own mail servers, so deliverability is handled.
Quickstart
- Sign in at demo.codeoutbox.com/signup — passwordless; you'll get an API key.
- Create a list (dashboard "+ Create list", or the API below).
- Embed the form on your site (dashboard "Copy embed").
- Send a Markdown newsletter with
co send.
The CLI talks to the API; configure it once:
export CO_URL=https://demo.codeoutbox.com
export CO_TOKEN=co_live_... # your API key
Capture subscribers
Every list has a form endpoint. Drop this anywhere — it works with no JavaScript (native POST → double opt-in):
<form action="https://demo.codeoutbox.com/f/<public_id>" method="POST">
<input type="email" name="email" required placeholder="you@example.com">
<button type="submit">Subscribe</button>
</form>
Or scaffold a styled, JS-enhanced version:
npx codeoutbox form --id <public_id> --base https://demo.codeoutbox.com
Submissions get a confirmation email (double opt-in). Unsubscribes and one-click List-Unsubscribe are handled for you.
Write & send
A campaign is Markdown with frontmatter, kept in your repo:
---
subject: Launch day 🚀
group: newsletter
preheader: We shipped.
---
Hi there 👋
We just **launched**. [Read the post](https://example.com/post).
co send launch.md # dry run: recipients + spam-lint
co send launch.md --live # actually send
Add send_at: 2026-07-01T09:00:00Z to the frontmatter to schedule it.
CLI reference
| Command | What it does |
|---|---|
co send <file> [--live] | Preview or send a campaign |
co sync [file] | Reconcile lists from codeoutbox.json |
co domains add|verify|list | Authenticate a sending domain |
co brand show|set | Per-tenant email branding |
co webhooks add|list|rm | Event webhooks |
co upgrade <plan> [--annual] | Stripe checkout |
co warmup | IP warmup status |
co token create | Mint an API key |
API
REST + Bearer auth (your API key). Base: https://demo.codeoutbox.com.
# create a list
curl -X POST $CO_URL/v1/groups -H "Authorization: Bearer $CO_TOKEN" \
-H 'Content-Type: application/json' -d '{"slug":"news","name":"News"}'
# add a (consented) subscriber
curl -X POST $CO_URL/v1/groups/news/subscribers -H "Authorization: Bearer $CO_TOKEN" \
-H 'Content-Type: application/json' -d '{"email":"a@example.com","confirmed":true}'
# send
curl -X POST $CO_URL/v1/broadcasts -H "Authorization: Bearer $CO_TOKEN" \
-H 'Content-Type: application/json' -d '{"source":"","confirm":true}'
Other endpoints: /v1/usage, /v1/broadcasts (list + stats), /v1/domains, /v1/webhooks, /v1/account (brand), /v1/billing/checkout.
Domain authentication
By default you send from our shared, authenticated domain. To send from your own domain (and remove limits), authenticate it:
co domains add news.yourdomain.com # prints SPF / DKIM / DMARC records
# publish those TXT records in your DNS, then:
co domains verify news.yourdomain.com
Once verified, broadcasts send from noreply@news.yourdomain.com, DKIM-signed with your own key. You can also do this from the dashboard "Sending domains" card.
Event webhooks
Get subscriber events POSTed to your app:
co webhooks add https://your-app.com/hook --events subscriber.confirmed,subscriber.bounced
Events: subscriber.confirmed subscriber.unsubscribed subscriber.bounced subscriber.complained. Each request is signed:
X-CO-Event: subscriber.confirmed
X-CO-Signature: t=<unix>,v1=<hex>
# verify: v1 == HMAC-SHA256(secret, `${t}.${rawBody}`)
Branding
Tenant email wears your brand, not ours. It auto-derives from your verified domain; override anytime:
co brand set --name "Acme" --color "#2E7D32" --logo https://acme.com/logo.png
Scheduling
Add send_at (ISO 8601, UTC) to the campaign frontmatter and co send --live queues it; a durable worker delivers it at the scheduled time:
---
subject: Weekly digest
group: newsletter
send_at: 2026-07-01T09:00:00Z
---
Coding agent (MCP)
CodeOutbox ships an MCP server, so an AI coding assistant can create lists, add subscribers, and send broadcasts (confirm-gated) for you — "set up my newsletter and send the launch" in one prompt.