> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sendpost.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Sending Emails via Postmark

> Send template-based emails through Postmark using the SendPost API with IP Pool routing and Postmark templates.

Once your Postmark provider and IP Pool are configured, you can send emails through Postmark using the standard SendPost API. Postmark is used for **template-based sending** only: you must specify a Postmark template alias.

<Warning>
  **Important**: When routing to Postmark you must include:

  * **`ippool`** – The SendPost IP Pool that routes traffic to your Postmark provider
  * **`tpspTemplate`** – The Postmark template alias (required; without it, send returns an error)
</Warning>

***

## Template-Based Sending (Required)

Postmark sends via the [Send email with template](https://postmarkapp.com/developer/api/templates-api#email-with-template) API. The template alias is taken from the `tpspTemplate` parameter and passed to Postmark as `TemplateAlias`. Custom data for the template comes from your request's custom fields (e.g. `customFields` / template model).

***

## Basic Template Email Example

```bash theme={null}
curl -X POST "https://api.sendpost.io/api/v1/subaccount/email/" \
  -H "X-SubAccount-ApiKey: YOUR_SENDPOST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "from": {
      "email": "sender@yourdomain.com",
      "name": "Your Name"
    },
    "to": [{
      "email": "recipient@example.com",
      "name": "Recipient Name"
    }],
    "subject": "Hello from SendPost via Postmark",
    "ippool": "postmark-pool",
    "tpspTemplate": "welcome-template",
    "trackOpens": true,
    "trackClicks": true
  }'
```

* **`ippool`**: SendPost IP Pool configured to route to your Postmark provider
* **`tpspTemplate`**: Postmark template alias (e.g. `welcome-template`) – **required** when sending via Postmark
* **`customFields`**: Object passed to Postmark as `TemplateModel` (use empty `{}` if no variables)

***

## Template with Personalization (Template Model)

Pass template variables via `customFields`; they are sent to Postmark as `TemplateModel`:

```bash theme={null}
curl -X POST "https://api.sendpost.io/api/v1/subaccount/email/" \
  -H "X-SubAccount-ApiKey: YOUR_SENDPOST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "from": {
      "email": "sender@yourdomain.com",
      "name": "Your Company"
    },
    "to": [{
      "email": "john@example.com",
      "name": "John Doe",
      "customFields": {
        "firstName": "John",
        "accountType": "Premium"
      }
    }],
    "subject": "Welcome {{firstName}}!",
    "ippool": "postmark-pool",
    "tpspTemplate": "welcome-template",
    "trackOpens": true,
    "trackClicks": true
  }'
```

Postmark will receive `TemplateModel` with these keys for use inside the template.

***

## Postmark Tag

Postmark supports a single `Tag` per email for categorization in dashboards and reports. SendPost maps the **first** entry of the `groups` array on the send request to Postmark's `Tag`.

* Pass `groups: ["transactional"]` to send `Tag: "transactional"` to Postmark
* Postmark accepts only one tag per email — additional entries in `groups` are dropped silently
* If `groups` is empty or omitted, no `Tag` is sent

```bash theme={null}
curl -X POST "https://api.sendpost.io/api/v1/subaccount/email/" \
  -H "X-SubAccount-ApiKey: YOUR_SENDPOST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "from": {
      "email": "sender@yourdomain.com",
      "name": "Your Company"
    },
    "to": [{
      "email": "recipient@example.com",
      "name": "Recipient Name"
    }],
    "subject": "Welcome!",
    "ippool": "postmark-pool",
    "tpspTemplate": "welcome-template",
    "groups": ["transactional"],
    "trackOpens": true,
    "trackClicks": true
  }'
```

The tag appears in Postmark's dashboard, in Postmark search, and on event payloads Postmark may send to your own webhooks.

***

## Custom Metadata

Postmark supports custom metadata attached to each email; it is visible in the Postmark dashboard, in Postmark search, and is included in payloads delivered to your own Postmark webhooks.

To attach custom metadata when sending via SendPost, add entries to the `headers` object in the request payload with keys prefixed by **`TPSP_METADATA_`** (case-insensitive). SendPost strips the prefix and forwards each key/value pair to Postmark as `Metadata`. The `TPSP_METADATA_*` entries are removed from the `Headers` array sent to Postmark and will **not** appear as MIME headers on the message Postmark relays. Other (non-prefixed) entries in `headers` continue to be passed to Postmark as regular MIME headers.

For example, `"TPSP_METADATA_order_id": "ORD-78921"` in the payload becomes `Metadata: { "order_id": "ORD-78921" }` on Postmark, while `"X-Entity-Ref-ID": "ORD-78921"` is forwarded to Postmark as a regular MIME header on the email itself.

```bash theme={null}
curl -X POST "https://api.sendpost.io/api/v1/subaccount/email/" \
  -H "X-SubAccount-ApiKey: YOUR_SENDPOST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "from": {
      "email": "sender@yourdomain.com",
      "name": "Your Company"
    },
    "to": [{
      "email": "john@example.com",
      "name": "John Doe"
    }],
    "subject": "Your order #ORD-78921 is confirmed",
    "ippool": "postmark-pool",
    "tpspTemplate": "order-confirmation",
    "groups": ["transactional"],
    "headers": {
      "X-Entity-Ref-ID": "ORD-78921",
      "List-Unsubscribe": "<mailto:unsubscribe@yourdomain.com>",
      "TPSP_METADATA_order_id": "ORD-78921",
      "TPSP_METADATA_customer_id": "cus_42a91b",
      "TPSP_METADATA_plan_tier": "premium",
      "TPSP_METADATA_campaign": "spring-launch-2026"
    },
    "trackOpens": true,
    "trackClicks": true
  }'
```

### Reserved Keys

The following keys are used by SendPost for webhook attribution and **cannot be overridden**. Entries like `TPSP_METADATA_accountId` are dropped silently:

* `accountId`
* `tpspId`
* `subAccountId`
* `emailType`
* `messageId`
* `messageSubject`

<Note>
  The customer's casing on the stripped key is preserved — Postmark accepts mixed-case keys, and SendPost does not normalize them. `TPSP_METADATA_OrderId` is sent to Postmark as `OrderId`, not `orderid`.
</Note>

### Limits

Postmark enforces the following limits. SendPost applies them before sending and **drops any entry that violates a limit** — the send still succeeds for the remaining metadata.

| Limit                                                              | Value          |
| ------------------------------------------------------------------ | -------------- |
| Maximum keys per email                                             | 25             |
| Maximum key length (after the `TPSP_METADATA_` prefix is stripped) | 50 characters  |
| Maximum value length                                               | 200 characters |

### Visibility

<Info>
  Custom metadata is visible in the **Postmark dashboard**, in **Postmark search**, and on payloads Postmark delivers to your own webhooks. SendPost does **not** store custom metadata in its analytics — it is not surfaced in SendPost events or dashboards.
</Info>

***

## Optional Parameters

| Parameter     | Description                                                                                                                                                                                                |
| ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `replyTo`     | Reply-to address (optional)                                                                                                                                                                                |
| `cc` / `bcc`  | Cc and Bcc recipients (optional)                                                                                                                                                                           |
| `groups`      | First entry is sent as Postmark's `Tag` (see [Postmark Tag](#postmark-tag))                                                                                                                                |
| `headers`     | Custom headers object; sent as `Headers` array to Postmark. Entries with keys prefixed `TPSP_METADATA_` are stripped and routed to Postmark's `Metadata` instead (see [Custom Metadata](#custom-metadata)) |
| `trackOpens`  | Enable open tracking (default: as configured)                                                                                                                                                              |
| `trackClicks` | Enable click tracking; maps to `TrackLinks`: "HtmlAndText" or "HtmlOnly"                                                                                                                                   |

SendPost also sends metadata (e.g. `accountId`, `tpspId`, `subAccountId`, `emailType`, `messageId`, `messageSubject`) to Postmark for webhook attribution; you do not need to set these manually.

***

## Message Stream

The **Message Stream** used for sending is the one you selected when creating the Postmark provider in SendPost. It is stored with the TPSP and sent with every request to Postmark; you do not pass it in each API call. The same stream is used for the webhook registered at setup.

***

## Response

**Success Response** (HTTP 200):

```json theme={null}
[
  {
    "messageId": "abc123-def456-ghi789",
    "errorCode": 0,
    "to": "recipient@example.com"
  }
]
```

On success, Postmark accepts the message and SendPost records a **PMProcessed** (ID: 69) event. Delivery, opens, clicks, bounces, and spam complaints are reported via webhooks and appear as PM\* event types in SendPost.

**Retries**: SendPost retries on 429 (rate limit) and 5xx from Postmark. On 4xx (except 429), no retry is performed.

***

## Next Steps

* [Understand event types](/guides/postmark/event-types) for PMProcessed, PMDelivered, PMOpen, etc.
* [View analytics](/guides/postmark/analytics) for your Postmark emails
* [Troubleshoot](/guides/postmark/troubleshooting) sending or template errors
