Skip to main content

Quickstart

From nothing to a delivered email. Every snippet on this page lives in packages/docs/examples/ and is typechecked against the current SDK in CI — if it compiles here, it compiles for you.

1. Install

npm install @mailroom/sdk
# bun add @mailroom/sdk · pnpm add @mailroom/sdk · yarn add @mailroom/sdk

Node 18+ (or any runtime with global fetch: Bun, Deno, Cloudflare Workers, Vercel Functions). No dependencies, ESM + CJS builds, types included.

2. Get an API key

In the Mailroom admin console: Settings → API keys → Create key. Choose the scopes the integration actually needs — send alone for transactional email, contacts:write if you also sync your list. See Authentication for the full scope list.

The key is shown once. Put it in your server environment:

MAILROOM_URL="https://mailroom.example.com" # your Mailroom deployment
MAILROOM_API_KEY="pk_live_…"
Server-side only

The key grants full access to the project it belongs to. Never ship it to a browser, a mobile app, or a public repo. Mailroom has no publishable key.

3. Verify the connection

health.ts
import { mailroom } from "./client";

// Cheapest possible check that the key, base URL, and network path all work.
const health = await mailroom.health();
console.log(health); // { service: "mailroom", sdk: "0.3.0" }

A MailroomAuthError here means the key is wrong or revoked; a MailroomConnectionError means the base URL or network path is wrong. Fix that before moving on — everything else depends on it.

4. Send your first email

Templates are enabled per project. welcome ships with Mailroom; swap in any key from mailroom.templates.list().

send.ts
import { createClient } from "@mailroom/sdk";

const mailroom = createClient({
apiKey: process.env.MAILROOM_API_KEY!,
baseUrl: process.env.MAILROOM_URL!,
});

const { id } = await mailroom.send({
to: "ada@example.com",
template: "welcome",
data: { name: "Ada" },
});

console.log(`queued send ${id}`);

send() resolves to { id } — the send-log id — or throws. Common failures:

ErrorcodeFix
MailroomValidationErrorunknown_templateThe template key does not exist in the registry.
MailroomValidationErrortemplate_not_enabledEnable it: templates.setEnabled(key, { enabled: true }).
MailroomValidationErrorno_brandThe project has no brand configured yet.
MailroomAuthErrorforbiddenThe key is missing the send scope.

Watch it land in Sends in the admin console, or read the log:

const [latest] = await mailroom.sends.list({ limit: 1 });
console.log(latest.status, latest.delivery_status);

5. Put contacts on the list

Sending to to: addresses works without ever creating a contact, but campaigns, sequences, and unsubscribe handling all key off the contact list.

contacts.ts
import { mailroom } from "./client";

// Upsert is idempotent on (project, email): safe to replay for the same person.
const contacts = await mailroom.contacts.upsert([
{ email: "ada@example.com", tags: ["beta"], source: "signup-form" },
{ email: "grace@example.com" },
]);

console.log(contacts.map((c) => `${c.email}${c.status}`));

Now you can send by contactId instead of to, and every marketing email automatically carries a working unsubscribe link.

Where to next

  • Sending — transactional vs marketing, brands, idempotency
  • Templates — what data a template accepts, publishing content
  • Sequences — lifecycle automation and event triggers
  • Webhooks — receive delivery and engagement events
  • Errors and retries — what to catch, what retries itself
  • SDK reference — generated from the SDK's types