README.md

September 16, 2026 · View on GitHub

MillionSend

The open-source email platform. Send one. Send a million.

Self-host on your own AWS SES, or use the hosted cloud. Resend-compatible API — migrating means changing two environment variables, not rewriting your integration.

The MillionSend dashboard: the Emails page, with each send's delivery status

Features

FeatureStatusNotes
Emails API (Resend-compatible)Send, batch, get, cancel — same request/response shapes as Resend.
IdempotencyIdempotency-Key header dedupes retried sends.
API keysCreate and revoke ms_ keys from the dashboard, with last-used tracking.
Suppression listHard bounces and complaints suppressed automatically; review and remove per address, or manage via /suppressions (batch add/remove up to 1000).
MetricsDaily sends with bounce and complaint rates tracked against SES thresholds.
Webhooks (Standard Webhooks)Signed event deliveries (webhook-* and svix-* headers) with per-endpoint event selection, a delivery log, and bring-your-own whsec_ secret.
Domains + BYODKIMGuided DNS verification; bring your own DKIM key or let SES manage it.
ContactsTeam-wide contacts with subscribe state, segments, topics, CSV import, and bulk POST /contacts/batch.
One-click unsubscribe (RFC 8058)List-Unsubscribe headers plus a hosted unsubscribe page.
BroadcastsCompose, schedule, and send to all contacts, a segment, or a topic; cancel while scheduled.
Templates + merge fieldsReusable templates with per-contact merge fields; /templates API with per-team aliases.
API request logsEvery API request recorded with request/response bodies, secrets redacted.
SMTP relayDrop-in SMTP on port 2587; authenticate with an API key.
Dashboard (en/pt-BR)Full dashboard in English and Brazilian Portuguese.
Self-host (Docker)Compose file plus a setup wizard; sends through your own AWS SES.
Migrate from Resendnpx @millionsend/cli migrate --from resend moves contacts, segments, topics, templates, webhooks, domains and suppressions; read-only against Resend, safe to re-run before cutover.
Content monitoringOptional outbound judge via TypeSafe Jev. Off by default on self-host.

The hosted monitor uses TypeSafe's Jev, a System One model built for typed decisions in software. After SES accepts a message, a sample is scored in the background; sending never waits on it. Self-hosters leave it off unless they set ABUSE_JUDGE=typesafe.

Run it locally

One command, in an empty directory — no clone needed:

npx @millionsend/setup

The wizard creates .env (secrets generated for you), optionally provisions the AWS resources (IAM user, SNS event topic, SES configuration set), and starts the prebuilt image with docker compose up -d. Every step is offered, skippable, and safe to re-run. Prefer doing it by hand? The manual curl path and everything else — from-source build, SES/SNS event pipeline, Docker-less development — is in SELF_HOSTING.md.

Dashboard at http://localhost:3000, API at http://localhost:3001.

License

Code is licensed under AGPL-3.0. SDKs ship separately under MIT (npm/PyPI package: millionsend).

The MillionSend name, wordmark, and logos are trademarks of the MillionSend project and are not licensed under the AGPL.

Community

Questions, ideas and roadmap talk live in the Discussions.