# Postmark (/docs/v/0.6.1/adapters/postmark)



The Postmark adapter calls the [Postmark Email API](https://postmarkapp.com/developer/api/email-api) over `fetch` — no extra dependency. Its distinctive feature is message streams: set `messageStream` once and every send routes through that Postmark stream.

<ProviderBadge adapter="postmark" />

## Configure [#configure]

Create a [server token](https://postmarkapp.com/developer/api/overview#authentication) for the server you send through, and make sure the sender signature or domain is approved in Postmark.

```ts title="lib/email.ts"
import { createEmailClient } from "@opencoredev/email-sdk";
import { postmark } from "@opencoredev/email-sdk/postmark";

export const email = createEmailClient({
  adapters: [
    postmark({
      serverToken: process.env.POSTMARK_SERVER_TOKEN!,
      messageStream: "outbound",
    }),
  ],
});
```

<TypeTable
  type="{
  serverToken: {
    description: &#x22;Postmark server token.&#x22;,
    type: &#x22;string&#x22;,
    required: true,
  },
  messageStream: {
    description: &#x22;Postmark message stream to send through.&#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.postmarkapp.com&#x22;',
  },
  fetch: {
    description: &#x22;Custom fetch implementation for tests or special runtimes.&#x22;,
    type: &#x22;typeof fetch&#x22;,
  },
  headers: {
    description: &#x22;Extra HTTP headers sent with every request.&#x22;,
    type: &#x22;Record<string, string>&#x22;,
  },
}"
/>

## Send [#send]

Postmark maps `cc`, `bcc`, `replyTo`, `headers`, `attachments`, `metadata`, and one tag.

```ts
const result = await email.send({
  from: "Acme <hello@acme.com>",
  to: "user@example.com",
  replyTo: "support@example.com",
  subject: "Your receipt for order ord_123",
  html: "<p>Thanks for your order.</p>",
  metadata: { orderId: "ord_123" },
  tags: [{ name: "type", value: "receipt" }],
});

console.log(result.id); // Postmark MessageID, also exposed as result.messageId
```

`metadata` becomes Postmark `Metadata`, and `result.accepted` echoes Postmark's `To` line.

<Callout type="warn" title="One tag per message">
  Postmark has a single `Tag` field. The adapter serializes the first tag as `name:value` and a
  second tag throws an `EmailValidationError` before any request is made. Need multiple tags?
  Check the [field support matrix](/docs/v/0.6.1/adapters/field-support).
</Callout>

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

```bash
POSTMARK_SERVER_TOKEN="..." npx email-sdk doctor --adapter postmark
```

```bash
POSTMARK_SERVER_TOKEN="..." npx email-sdk send \
  --adapter postmark \
  --message-stream outbound \
  --from "Acme <hello@acme.com>" \
  --to user@example.com \
  --subject "Postmark smoke test" \
  --text "It works" \
  --dry-run
```

The token also accepts the `--server-token` flag. Drop `--dry-run` for one real send — that is the only check that proves the server token, sender signature, and message stream are ready.
