# Lettermint (/docs/adapters/lettermint)



The Lettermint adapter calls Lettermint's `POST /v1/send` endpoint over `fetch` — no extra dependency. [Lettermint](https://lettermint.co/?ref=emailsdk) 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.

<ProviderBadge adapter="lettermint" />

## Configure [#configure]

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

```ts title="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! })],
});
```

<TypeTable
  type="{
  apiToken: {
    description: &#x22;Lettermint API token (prefixed lm_), sent in the x-lettermint-token header.&#x22;,
    type: &#x22;string&#x22;,
    required: true,
  },
  route: {
    description: &#x22;Optional Lettermint route slug. Defaults to the project's default route.&#x22;,
    type: &#x22;string&#x22;,
  },
  baseUrl: {
    description: &#x22;Override the API origin, e.g. for a proxy.&#x22;,
    type: &#x22;string&#x22;,
    default: '&#x22;https://api.lettermint.co/v1&#x22;',
  },
  fetch: {
    description: &#x22;Custom fetch implementation for tests or special runtimes.&#x22;,
    type: &#x22;typeof fetch&#x22;,
  },
  headers: {
    description: &#x22;Extra headers merged into every request.&#x22;,
    type: &#x22;Record<string, string>&#x22;,
  },
}"
/>

## Send [#send]

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

```ts
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
```

<Callout type="warn" title="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.
</Callout>

<Callout title="From a verified sending domain">
  The sender domain in `from` must be verified for your Lettermint project, and a single message may
  not exceed 50 recipients across `to`, `cc`, and `bcc` combined.
</Callout>

## Idempotent sends [#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.

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

## Routes [#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.

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

## Verify from the CLI [#verify-from-the-cli]

```bash
LETTERMINT_API_TOKEN="lm_..." npx email-sdk doctor --adapter lettermint
```

```bash
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` for one real smoke send — the only check that proves the API token and sending domain are ready.
