Migration von Postmark
Diese Seite ordnet Postmarks Send-Payload, Suppression-Exporte und Webhooks Bird zu. Folgen Sie dem Hauptleitfaden zur Migration 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, 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.
Codebeispiel
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 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.
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.
- 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 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 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:
- 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 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 HMAC-Schema, sodass Ihr Handler einen Verifizierungsschritt erhält, den er bisher nicht hatte. Die Anleitung finden Sie unter Webhooks und Events. 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 und den Sandbox-Smoke-Test im Hauptleitfaden durch. Beide sind anbieterunabhängig.
Nächste Schritte
- Sending-Domains: Registrierung, Verifizierungslebenszyklus und die DNS-Records, die Sie veröffentlichen
- Webhooks und Events: Endpoint-Einrichtung und Standard-Webhooks-Verifizierung
- Test-Sandbox: Smoke-Test der neuen Integration vor der Umstellung
- Suppressions: Bestätigen Sie Ihre importierte Liste und wie wir sie ab jetzt pflegen
Verwandte Ressourcen
Weiter mit der Dokumentation, Anleitungen und Beispielen zu diesem Thema. Die Ressourcen sind auf Englisch.
Anleitung ansehenGetting started with emailDie Funktion erkundenEmailDem Lernpfad folgenBuild your first integrationImplementierungsleitfadenSend your first email
Übung ausprobieren und ein Implementierungs-Briefing erhalten