Email marketing for teams, apps and agents.
Manage contacts, design templates, send broadcasts and run automated sequences, through a dashboard,
a REST API, an MCP server and an embeddable email editor. Bring your own SMTP provider.
Sending one email is easy. Running email marketing means you also need an audience database, a composer, segmentation, drip automations, unsubscribe handling, open and click tracking, suppression lists, and a way to give your app and your AI tools safe access to all of it. SendLit is that layer, in one open-source stack.
- Broadcasts and sequences share one model. A broadcast is a one-off sequence with a single email; a sequence is a multi-step automation enrolled by event triggers.
- Team-scoped everything. Each team owns its contacts, templates, sending provider, API keys and quota, so one deployment can serve many brands or clients.
- Bring your own sending provider. Plug in any SMTP service (SES, SendGrid, Postmark, Mailgun and so on). Credentials are stored encrypted.
- Built for agents. Claude, ChatGPT, Cursor and any MCP client can work with your audience and campaigns over OAuth.
- Embeddable editor. The WYSIWYG email editor and the composing blocks are published as React packages you can use in your own product.
- Deliverability basics included. Contact filters and tags, suppression lists, one-click unsubscribe, transactional sends and tracking.
- Open source and portable. Self-host the whole thing with one
docker compose up.
The fastest way to try SendLit is the Docker Compose stack, which runs PostgreSQL, Redis, the API and the dashboard:
git clone https://github.com/codelitdev/sendlit.git
cd sendlit
cp .env.example .env
# Fill in the required secrets in .env (generation commands are included as comments).
docker compose up --build -d
docker compose logs initOpen the dashboard at http://localhost:3000, sign in with an email one-time code, and follow Send your first broadcast.
BOOTSTRAP_ORGANIZATION_OWNER_EMAIL selects an ordinary initial organization
owner; it does not create a special global-admin role. To integrate
headlessly, set BOOTSTRAP_DELIVERY_SETUP_API_KEY and BOOTSTRAP_TEAM_PROVISIONING_API_KEY in
.env. Bootstrap hashes both keys and never logs them.
See the Headless organization setup
for the complete REST sequence, scopes, rotation, and migration from the old
log-generated key. The plain Markdown guide is at
apps/docs/integrations/headless-provisioning.md.
Create a team API key in the dashboard (Settings → API keys) and call the API with it:
curl http://localhost:4000/contacts \
-H "x-sendlit-apikey: sl_live_..."Connect an AI agent: add https://api.sendlit.app/mcp (or http://localhost:4000/mcp for your own Compose instance) as a remote MCP server in your client and sign in. See the MCP guide.
| Package | Description | License |
|---|---|---|
@sendlit/email-editor |
WYSIWYG email editor | MIT |
@sendlit/email-blocks |
Headless composing blocks for broadcasts, sequences and templates | MIT |
@sendlit/api-contract |
Shared REST API contract (schemas and types) | MIT |
The repository also contains the API (apps/api), which owns all product behavior including the MCP server; the dashboard (apps/web), a Next.js client over the API; and the docs site (apps/docs).
Tech stack: TypeScript, PostgreSQL, Redis, BullMQ, Next.js, Tailwind CSS and shadcn/ui.
The root Compose stack runs PostgreSQL, Redis, the API and the web dashboard, plus a one-shot init service that applies migrations and creates the initial owner's organization and default team. The API reports /ready once Postgres and Redis answer, and the dashboard waits for it.
- Set
BOOTSTRAP_ORGANIZATION_OWNER_EMAILand the required secrets in.envbefore the first start. - Run
docker compose up --build -d. Theinitservice applies migrations and creates the owner's organization and default team. - Open the dashboard at
WEB_CLIENT(defaulthttp://localhost:3000) and the API documentation atAPI_PUBLIC_URL/docs. - Configure a sending provider for your team in the dashboard settings. Without one, SendLit won't send campaign mail.
For an internet-facing deployment:
- Set
API_PUBLIC_URL,WEB_CLIENT,PROTOCOL=httpsandDOMAINto the public values before the first start. - Put the API and web ports behind a TLS reverse proxy, and set
ENABLE_TRUST_PROXY=truewhen it forwards client IPs. - Back up the
postgres-datavolume and keep the.envsecrets stable. Changing the ESP encryption key makes stored team SMTP credentials unreadable. - If you send through Amazon SES, follow Amazon SES bounces and complaints so SendLit suppresses bounced and complaining addresses.
Prebuilt images are published on release tags: codelit/sendlit (API) and codelit/sendlit-web (dashboard).
Requirements: Bun 1.4.1 and Docker. We develop on Linux; on Windows, use WSL.
SendLit follows the CodeLit Platform conventions: one Bun workspace, the API runs its TypeScript directly on Bun, and shared infrastructure comes from the published @codelitdev/* packages.
bun install
# 1. Start Postgres, Redis and Mailpit for local development.
docker compose -f docker-compose.local.yml up -d
# 2. Configure the API and create its tables.
cp apps/api/.env.example apps/api/.env
bun --filter @sendlit/api db:migrate
# 3. Build the shared packages once so the API and dashboard can import them.
bun run build:packages
# 4. Configure the dashboard (API_URL must point at the API).
cp apps/web/.env.example apps/web/.env.local
bun run dev:api # API
bun run dev:web # Dashboard on http://localhost:3000
bun run dev:docs # Docs siteThe local Compose file publishes Postgres on 5434, Redis on 6380 and Mailpit on 1027 (SMTP) and 8027 (UI), so it can run next to the CourseLit and FrontLit local stacks. apps/api/.env.example already points at those ports. Bun loads apps/api/.env automatically.
Re-run bun run build:packages (or use the packages' dev scripts) after changing @sendlit/email-editor or @sendlit/email-blocks.
bun run test # API, web and package unit tests
bun --filter @sendlit/api test:conformance # CodeLit Platform conformance
bun --filter @sendlit/api check:drift # billing and Better Auth schema drift
bun run typecheck # TypeScript in every workspace
bun run lint # Biome lint
bun run format # Biome format (bun run format:check in CI)Cloud billing recovery is a CLI, not the dashboard. From the repo root it
loads apps/api/.env and talks to that API's database:
bun --filter @sendlit/api billing catalog-status
bun --filter @sendlit/api billing catalog-verifyRun it with no arguments for the full list. Subcommands:
catalog-status/catalog-verify/catalog-abandon <revision> --reason <text>reconcile-org <organization_public_id>webhook-retry <provider_event_id>/webhook-inspect <provider_event_id>set-override <organization_public_id> --teams <n>|none --contacts <n>|none --reason <text>reputation-apply <team_public_id> <warned|marketing_paused|all_paused> --operator <user_id> --reason <text>reputation-release <team_public_id> --operator <user_id> --reason <text>cancel-subscription <organization_public_id> --reason <text>
OSS mode has nothing to verify. A new BILLING_CATALOG_REVISION is recorded on
API startup; catalog-verify checks it against Dodo and activates it.
Product, API and email-block docs live in apps/docs. The REST reference is generated from the API contract, and the running API serves interactive documentation at /docs.
Contributions are welcome. For anything larger than a small fix, please open an issue first so we can agree on the approach.
- Fork the repository and create a branch.
- Make your change, with tests. If you change a published package, add a changeset with
bun run changeset. - If you change
apps/api, update the REST API documentation and the MCP server too. - Run
bun run lint,bun run format,bun run typecheckandbun run test. - Open a pull request.
Questions and ideas are welcome in GitHub issues.
Please don't report security issues in public issues. Report them privately through GitHub's security advisories.
SendLit is split into two licenses:
- AGPL-3.0-or-later covers the server (
apps/api), the dashboard (apps/web), the docs site (apps/docs) and internal tooling. If you run a modified SendLit as a hosted service, you must share your changes under the same license. Self-hosting is free. - MIT covers the packages you embed in your own products:
@sendlit/email-editor,@sendlit/email-blocksand@sendlit/api-contract. Each published package declares MIT in itspackage.json.
The AGPL license text is in LICENSE.
SendLit grew out of the email capabilities of CourseLit and shares its OAuth2 foundations with MediaLit.