# Migration von Postmark

Diese Seite ordnet Postmarks Send-Payload, Suppression-Exporte und Webhooks Bird zu. Folgen Sie dem [Hauptleitfaden zur Migration](/docs/guides/email/migrate) der Reihe nach und verwenden Sie diese Zuordnungen für die Schritte 1, 3 und 4.

Postmarks Dokumentation gibt an, dass es "does not currently support HMAC webhook signature verification" (gelesen September 2026), daher fügt Schritt 4 eine Verifizierung hinzu, die Ihr Handler heute nicht hat. Lesen Sie [Webhook-Events übersetzen](#webhook-events-übersetzen), bevor Sie die Umstellung planen.

## Übergeben Sie dies Ihrem Agenten

Fügen Sie dies in Claude Code, Cursor oder Codex ein. Der Agent arbeitet diese Seite gegen Ihr eigenes Repository ab und nutzt die Bird-Oberfläche, die er bereits hat: den MCP-Server, falls einer verbunden ist, oder die CLI, falls sie installiert und angemeldet ist.

```text
I am moving an email integration from Postmark to Bird. Route through it with me.
1. Check what you already have before setting anything up. If Bird's MCP server is connected, use its tools. If the Bird CLI is installed and signed in, use that. Either one is enough, and every step below is an action you take with whichever you have. Only if neither is present, follow https://bird.com/docs/ai/set-up-your-agent.md to set one up and sign me in. Every Bird docs page serves Markdown at its own URL with `.md` appended, so fetch that rather than the HTML.
2. Read https://bird.com/docs/guides/email/migrate/postmark.md for the payload, suppression and webhook mapping, and https://bird.com/docs/guides/email/migrate.md for the order the steps go in.
3. Find and list my Postmark usage in this repository before you change anything: calls to /email and /email/withTemplate and any SDK wrappers around them, every MessageStream name I send on, the webhook handler and the URL it is registered at, and every domain I send from. Tell me the list before you edit anything.
4. Register each of those sending domains with Bird and give me the DNS records to publish, following https://bird.com/docs/guides/email/sending-domains.md. Leave every DNS record Postmark uses exactly as it is: Bird's records are published alongside them and both providers authenticate side by side until I switch traffic. Publishing DNS affects mail for the whole domain, so show me the records and let me publish them.
5. Export my suppressions and import them into Bird before any production traffic goes through Bird, so my first sends do not reach addresses that already bounced or complained. Postmark keeps suppressions per message stream, so dump GET /message-streams/{stream_id}/suppressions/dump once for every stream I send on rather than only the default outbound stream. The Bird import takes one address per request and is idempotent, so a partial re-run is safe. https://bird.com/docs/guides/email/suppressions.md has the reason taxonomy.
6. Port the send call and the webhook handler using the mapping tables on the provider page. Postmark's docs say it does not currently support HMAC webhook signature verification, so my handler probably has no signature check and adding one is new code rather than a swap. If my registered Postmark webhook URL carries HTTP Basic credentials, take them out and tell me to rotate that pair rather than reusing it on the Bird endpoint: a URL-embedded credential should be treated as exposed. https://bird.com/docs/guides/webhooks.md and https://bird.com/docs/guides/email/events.md.
7. Run my whole integration against Bird's mail sandbox before any production traffic, following https://bird.com/docs/guides/email/testing-sandbox.md. Sandbox sends run the real pipeline without reaching an inbox or touching my sending reputation.
8. Stop and ask me wherever a step needs a decision. Do not point production traffic at Bird until I have seen the sandbox results and replied with the words cut over to Bird. Retiring the Postmark path is a separate step that comes later: ask me again and wait for me to reply with the words retire the Postmark path. A reply that agrees without naming what it is authorising is not authorisation. Finish by telling me what is left that only a person can do.
```

## Den Send-Call zuordnen

Postmark verteilt den Versand auf zwei Endpoints: `POST /email` für eine zusammengestellte Nachricht und `POST /email/withTemplate` für ein gespeichertes Template. Unser [`POST /v1/email/messages`](/docs/api/reference/create-email-message) ist ein einzelner Endpoint für beides, wobei das Template in einem Feld referenziert wird.

| Funktion               | Postmark                                                  | Bird                                                    |
| ---------------------- | --------------------------------------------------------- | ------------------------------------------------------- |
| Auth                   | `X-Postmark-Server-Token`-Header                          | `Authorization: Bearer`                                 |
| Absender               | `From`                                                    | `from`                                                  |
| Empfänger              | `To` / `Cc` / `Bcc` (kommagetrennt, max. 50)              | `to` / `cc` / `bcc` (Arrays)                            |
| Betreff                | `Subject`                                                 | `subject`                                               |
| Body                   | `HtmlBody` / `TextBody`                                   | `html` / `text` (mindestens eins)                       |
| Reply-to               | `ReplyTo` (kommagetrennt)                                 | `reply_to` (Array)                                      |
| Eigene Header          | `Headers` (`Name`/`Value`-Objekte)                        | `headers` (String → String-Objekt)                      |
| Filterbares Label      | `Tag` (eins pro Nachricht)                                | `tags`: `{name, value}`-Paare                           |
| Roundtrip-Kontext      | `Metadata`                                                | `metadata`: beliebiger JSON                             |
| Gespeichertes Template | `TemplateId` / `TemplateAlias` + `TemplateModel`          | `template` + `template.parameters`                      |
| Open-Tracking          | `TrackOpens`                                              | `track_opens` (Standard `true`)                         |
| Click-Tracking         | `TrackLinks` (`None`/`HtmlAndText`/`HtmlOnly`/`TextOnly`) | `track_clicks` (Boolean, siehe unten)                   |
| Anhänge                | `Attachments` (`Name`, `Content`, `ContentType`)          | `attachments`                                           |
| Traffic-Trennung       | `MessageStream`                                           | (kein Gegenstück, siehe unten)                          |
| Kategorie              | (keine)                                                   | `category`: `marketing` (Standard) oder `transactional` |
| Zeitplanung            | (keine)                                                   | `scheduled_at`                                          |

Unsere Feldlimits und Standardwerte (Empfängeranzahl, Tag- und Metadaten-Limits) finden Sie unter [E-Mail senden](/docs/guides/email/sending-email).

Hinweise zur Portierung:

- **Empfänger sind bei Postmark Strings und hier Arrays.** `"a@x.com, b@x.com"` wird zu `["a@x.com", "b@x.com"]`. Wenn Ihr Code diesen String durch Zusammenfügen einer Liste erzeugt, löschen Sie das Zusammenfügen statt der Liste.
- **`Tag` ist ein einzelner String pro Nachricht. Unsere `tags` sind Paare, und es kann mehrere geben.** Ein Tag wie `"welcome"` wird zu `{"name": "category", "value": "welcome"}`. Wählen Sie einen stabilen `name`, damit Ihre Dashboards so filtern wie zuvor Ihre Postmark-Tag-Statistiken.
- **`Metadata` wird direkt übernommen, und wir geben es zurück.** Wir liefern Ihren `metadata` (und `tags`) bei jedem Webhook-Event zusammen mit `email_id`/`recipient_id` zurück, sodass Ihre Handler den Kontext ohne zusätzlichen Lookup erhalten.
- **Click-Tracking ist dort ein Enum und hier ein Boolean.** `TrackLinks: "None"` entspricht `track_clicks: false`; die drei aktivierten Werte werden alle zu `track_clicks: true`, weil wir HTML- und Text-Teile nicht getrennt tracken.
- **Templates gehen in denselben Call.** Es gibt keinen separaten Template-Endpoint: `TemplateId` oder `TemplateAlias` wird zu `template` (per ID oder Slug) und `TemplateModel` wird zu `template.parameters`, auf `POST /v1/email/messages`. Siehe [Senden mit einem Template](/docs/guides/email/sending-email#sending-with-a-template).
- **Ein Message Stream hat kein Gegenstück, und `category` ist keins.** Ein Stream ist ein Container mit eigener Suppression-Liste, eigenen Statistiken und eigenen Webhooks. Unsere [Kategorie](/docs/guides/email/categories) ist ein Flag pro Nachricht mit einer einzigen Wirkung: Sie bestimmt, welche Suppression-Einträge und Abmeldepräferenzen diese Nachricht blockieren können. `category: transactional` zu setzen, weil eine Nachricht aus einem transaktionalen Stream kam, ist meistens richtig, aber es ist eine Aussage über den Sendezweck und keine Portierung des Streams. Nichts hier reproduziert Per-Stream-Statistiken oder Per-Stream-Suppression-Scoping; verwenden Sie [Tags](/docs/guides/email/sending-email#tags-vs-metadata) für die Aufschlüsselung im Reporting.

## Suppressions exportieren

Postmark speichert Suppressions **pro Message Stream**, es gibt also keine einzelne kontoweite Liste zum Abrufen. Exportieren Sie für jeden Stream, über den Sie senden, die Liste und führen Sie das Ergebnis durch die [Import-Schleife](/docs/guides/email/migrate#3-import-suppressions):

- `GET /message-streams/{stream_id}/suppressions/dump`

Listen Sie zuerst Ihre Streams auf und exportieren Sie jeden, über den Sie noch senden. Wenn Sie den Standard-`outbound`-Stream so behandeln, als wäre er die gesamte Liste, übernehmen Sie die transaktionalen Suppressions und verpassen die Broadcast-Suppressions – und Sie erfahren es erst, indem Sie Personen anschreiben, die sich abgemeldet haben. Die `SuppressionReason`-Werte sind `HardBounce`, `SpamComplaint` und `ManualSuppression`, die auf unsere `hard_bounce`-, `complaint`- und `manual`-Gründe abgebildet werden. [Suppressions](/docs/guides/email/suppressions) enthält die vollständige Taxonomie.

## Webhook-Events übersetzen

Postmark sendet einen Webhook-Typ pro Event und identifiziert ihn über das `RecordType`-Feld in der Payload.

| Ergebnis               | Postmark                        | Bird                                             |
| ---------------------- | ------------------------------- | ------------------------------------------------ |
| Akzeptiert/verarbeitet | (die API-Antwort)               | `email.accepted` → `email.processed`             |
| Zugestellt             | `Delivery`                      | `email.delivered`                                |
| Temporärer Fehler      | `Bounce` mit transientem `Type` | `email.deferred`                                 |
| Permanenter Bounce     | `Bounce` mit `Type: HardBounce` | `email.bounced` / `email.out_of_band_bounce`     |
| Spam-Beschwerde        | `SpamComplaint`                 | `email.complained`                               |
| Blockiert/unterdrückt  | (keine)                         | `email.rejected`                                 |
| Öffnung                | `Open`                          | `email.opened`                                   |
| Klick                  | `Click`                         | `email.clicked`                                  |
| Abmeldung              | `SubscriptionChange`            | `email.unsubscribed` / `email.list_unsubscribed` |

Zwei Unterschiede bestimmen, wie stark sich Ihr Handler ändert.

**Verifizierung ist neuer Code, kein Austausch.** Postmarks Dokumentation gibt an, dass es "does not currently support HMAC webhook signature verification" (gelesen September 2026), und empfiehlt HTTP Basic-Credentials, die in die registrierte URL eingebettet sind (`https://<username>:<password>@example.com/webhook`), plus seine IP-Bereiche in Ihrer Firewall. Wir signieren jede Zustellung gemäß dem [Standard Webhooks](https://www.standardwebhooks.com) HMAC-Schema, sodass Ihr Handler einen Verifizierungsschritt erhält, den er bisher nicht hatte. Die Anleitung finden Sie unter [Webhooks und Events](/docs/guides/webhooks). Führen Sie diesen Schritt zuerst aus: Ein Handler, der unsignierte Requests akzeptiert, ist das Einzige, was die Migration nicht übernehmen sollte.

**Rotieren Sie die Credentials, statt sie wiederzuverwenden.** Ein Benutzername und Passwort, das in einer Webhook-URL gelebt hat, sollte als exponiert behandelt werden, denn URLs gelangen in Access-Logs, Konfigurationsexporte und Vendor-Konsolen. Entfernen Sie sie vom Endpoint und erstellen Sie ein neues Paar, falls etwas anderes sie noch benötigt; übernehmen Sie das alte Paar nicht auf den Bird-Endpoint, der stattdessen per Signatur authentifiziert.

**Postmark meldet Hard- und Soft-Bounces als einen `Bounce`-Datensatz mit einem `Type`-Feld. Wir melden sie als unterschiedliche Events.** Ein Handler, der innerhalb einer Bounce-Payload nach `Type` verzweigt, verzweigt hier stattdessen nach dem Event-Namen: Transiente Fehler kommen als `email.deferred` und permanente als `email.bounced`. Jeden Bounce-Typ, den Postmark unterscheidet, finden Sie in seiner Bounce-API-Referenz; für die Portierung zählt, auf welcher Seite dieser Aufteilung er landet.

Unsere Zustellevents sind empfängerbezogen (`recipient_id` neben `email_id`), sodass ein Versand an drei Empfänger drei Zustellergebnisse statt eines erzeugt.

## Umstellung

Arbeiten Sie [Domains und DNS](/docs/guides/email/migrate#2-re-point-domains-and-dns) und den [Sandbox-Smoke-Test](/docs/guides/email/migrate#5-verify-in-the-sandbox-before-cutover) im Hauptleitfaden durch. Beide sind anbieterunabhängig.

## Nächste Schritte

- [Sending-Domains](/docs/guides/email/sending-domains): Registrierung, Verifizierungslebenszyklus und die DNS-Records, die Sie veröffentlichen
- [Webhooks und Events](/docs/guides/webhooks): Endpoint-Einrichtung und Standard-Webhooks-Verifizierung
- [Test-Sandbox](/docs/guides/email/testing-sandbox): Smoke-Test der neuen Integration vor der Umstellung
- [Suppressions](/docs/guides/email/suppressions): Bestätigen Sie Ihre importierte Liste und wie wir sie ab jetzt pflegen

## Related resources

- [Getting started with email](/learn/email/getting-started-with-email) (video)
- [Email](/products/email) (product)
- [Build your first integration](/learn/paths/integration) (course)
- [Send your first email](/docs/get-started/send-your-first-email) (docs)

[Get an implementation brief](/learn/workspace?topic=email)
