Mailroom
Mailroom is a multi-tenant email platform: first-party contacts, template
rendering, transactional and marketing sends, lifecycle sequences, and campaigns
— exposed as an HTTP API (/api/v1) with a typed TypeScript client,
@mailroom/sdk.
Your product calls Mailroom; Mailroom owns the list, the rendering, the sending, the suppressions, and the engagement data.
const { id } = await mailroom.send({
to: "ada@example.com",
template: "welcome",
data: { name: "Ada" },
});
Server-to-server only
An API key (pk_live_…) is a secret with full project access. It belongs on
a server, in a worker, or in a build step — never in a browser bundle, a mobile
app, or anything a user can read. There is no public/publishable key variant and
no CORS story: Mailroom is not designed to be called from client code.
See Authentication.
How the pieces fit
| Concept | What it is |
|---|---|
| Contact | A person on your list, unique per project by email, with status, tags, and consent metadata. |
| Template | Code-defined email in the registry, enabled per project, rendered with data you pass at send time. |
| Send | One email attempt. Logged with delivery and engagement state as webhooks land. |
| Campaign | One-off send to an audience (everyone, a tag, a segment, or an explicit list), optionally scheduled and A/B split. |
| Sequence | A flow graph (trigger → wait → send → branch) that contacts move through as enrollments. |
| Segment | A saved audience filter, evaluated at send time. |
| Suppression | An address Mailroom will not send to (bounce, complaint, or manual). |
| Webhook | Your endpoint, receiving signed events (email.bounced, contact.unsubscribed, …). |
Tenancy: Org → Project → Brand
Every row in Mailroom is scoped by project. A project owns its contacts, API keys, sending domains, templates, and unsubscribe secret — two projects never see each other's data.
A brand is a sending identity inside a project (from-address, theme). Most
integrations use one brand and can ignore the parameter; multi-brand setups pass
brand per call or set defaultBrand on the client.
An org groups projects for billing and team access. It never appears in the API surface: your key already resolves to exactly one project.
The SDK versus raw HTTP
The SDK is a thin, dependency-free wrapper: one method per endpoint, resolving to the response data and throwing typed errors. It adds retries with jittered backoff, automatic idempotency keys on mutations, cursor pagination helpers, and webhook signature verification — all of which you would otherwise write yourself.
If you are not on TypeScript or JavaScript, call the REST API directly; the endpoint reference documents the same surface, including the scopes each route requires.