Email SDK
Adapters

Lettermint

Send through Lettermint's European transactional email API with CC, BCC, reply-to, headers, metadata, tags, base64 attachments, idempotent retries, and routes.

Capabilities

Repeated headersIdempotencySchedulingPersonalized
NonativeNoexpanded

These values come from the adapter's exported capabilities declaration. The field support matrix covers normalized message fields.

The Lettermint adapter calls Lettermint's POST /v1/send endpoint with plain fetch. Lettermint is a European transactional email service with a REST API, SMTP relay, routes, and built-in open/click tracking. The adapter maps the normalized EmailMessage straight onto its send payload and authenticates with the x-lettermint-token header.

Lettermint logo
Lettermint@opencoredev/email-sdk/lettermint
Provider docs

Configure

Create a Lettermint API token (prefixed lm_) for the project you send from, and verify the sending domain.

lib/email.ts
import { createEmailClient } from "@opencoredev/email-sdk";
import { lettermint } from "@opencoredev/email-sdk/lettermint";

export const email = createEmailClient({
  adapters: [lettermint({ apiToken: process.env.LETTERMINT_API_TOKEN! })],
});

Prop

Type

Send

Lettermint accepts multiple recipients, CC, BCC, reply-to, custom headers, metadata, and attachments. Attachments are base64-encoded automatically.

const result = await email.send({
  from: "Acme <hello@acme.com>",
  to: "user@example.com",
  subject: "Welcome to Acme",
  html: "<p>Thanks for joining Acme.</p>",
  text: "Thanks for joining Acme.",
});

console.log(result.id); // Lettermint message_id

One tag per message

Lettermint represents a single freeform tag per email. The adapter sends the first tag's value and fails fast with an EmailValidationError if a message carries more than one tag. Metadata values are coerced to strings to match Lettermint's metadata shape.

From a verified sending domain

The sender domain in from must be verified for your Lettermint project. Lettermint also caps a message at 50 recipients across to, cc, and bcc combined; the adapter does not pre-check this, so an oversized send fails at the API.

Idempotent sends

Pass an idempotencyKey and the adapter forwards it as Lettermint's Idempotency-Key header, so a retried send with the same key replays the original result instead of sending twice.

await email.send(message, { idempotencyKey: "receipt:order_123" });

Routes

Lettermint routes separate transactional and broadcast streams. Pass a route to target a specific one; omit it to use the project's default route.

const email = createEmailClient({
  adapters: [lettermint({ apiToken: process.env.LETTERMINT_API_TOKEN!, route: "transactional" })],
});

Verify from the CLI

LETTERMINT_API_TOKEN="lm_..." npx email-sdk doctor --adapter lettermint
LETTERMINT_API_TOKEN="lm_..." npx email-sdk send \
  --adapter lettermint \
  --from "Acme <hello@acme.com>" \
  --to user@example.com \
  --subject "Lettermint smoke test" \
  --text "It works" \
  --dry-run

Drop --dry-run to send for real. Route resolution only happens on Lettermint's end, so this doubles as your route check: a live send with LETTERMINT_ROUTE set proves that slug exists, and one without it proves your project's default route works.

On this page