Migreren vanuit Postmark
Deze pagina vertaalt Postmarks verzendpayload, suppressiedumps en webhooks naar Bird. Volg de hoofdmigratiegids op volgorde en gebruik deze vertalingen voor stap 1, 3 en 4.
De documentatie van Postmark vermeldt dat het "does not currently support HMAC webhook signature verification" (gelezen september 2026), dus stap 4 voegt verificatie toe die je handler nu niet heeft. Lees Webhookevents vertalen voordat je de cutover plant.
Geef dit aan je agent
Plak dit in Claude Code, Cursor of Codex. De agent werkt deze pagina door tegen je eigen repository, via het Bird-oppervlak dat hij al heeft: de MCP-server als er een is verbonden, de CLI als die is geïnstalleerd en ingelogd.
Codevoorbeeld
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.Vertaal de verzendaanroep
Postmark verdeelt het verzenden over twee endpoints: POST /email voor een samengesteld bericht en POST /email/withTemplate voor een opgeslagen template. Ons POST /v1/email/messages is één endpoint voor beide, met het template als veldverwijzing.
| Wat het doet | Postmark | Bird |
|---|---|---|
| Authenticatie | X-Postmark-Server-Token-header | Authorization: Bearer |
| Afzender | From | from |
| Ontvangers | To / Cc / Bcc (kommagescheiden, max. 50) | to / cc / bcc (arrays) |
| Onderwerp | Subject | subject |
| Body | HtmlBody / TextBody | html / text (minstens één) |
| Reply-to | ReplyTo (kommagescheiden) | reply_to (array) |
| Aangepaste headers | Headers (Name/Value-objecten) | headers (string → string-object) |
| Filterbaar label | Tag (één per bericht) | tags: {name, value}-paren |
| Round-tripcontext | Metadata | metadata: willekeurige JSON |
| Opgeslagen template | TemplateId / TemplateAlias + TemplateModel | template + template.parameters |
| Open tracking | TrackOpens | track_opens (standaard true) |
| Kliktracking | TrackLinks (None/HtmlAndText/HtmlOnly/TextOnly) | track_clicks (boolean, zie hieronder) |
| Bijlagen | Attachments (Name, Content, ContentType) | attachments |
| Verkeerssplitsing | MessageStream | (geen equivalent, zie hieronder) |
| Categorie | (geen) | category: marketing (standaard) of transactional |
| Planning | (geen) | scheduled_at |
De limieten en standaardwaarden van onze velden (aantallen ontvangers, tag- en metadatalimieten) staan in E-mail verzenden.
Opmerkingen bij het porten:
- Ontvangers zijn strings in Postmark en arrays hier. "a@x.com, b@x.com" wordt ["a@x.com", "b@x.com"]. Als je code die string opbouwt door een lijst te joinen, verwijder dan de join in plaats van de lijst.
- Tag is één string per bericht. Onze tags zijn paren, en er kunnen er meerdere zijn. Een tag als "welcome" wordt {"name": "category", "value": "welcome"}. Kies een stabiele name zodat je dashboards op dezelfde manier filteren als je Postmark-tagstatistieken deden.
- Metadata vertaalt direct, en we sturen het terug. We retourneren je metadata (en tags) bij elk webhookevent samen met email_id/recipient_id, zodat je handlers je context terugkrijgen zonder een lookup.
- Kliktracking is daar een enum en hier een boolean. TrackLinks: "None" is track_clicks: false; de drie ingeschakelde waarden worden allemaal track_clicks: true, omdat we HTML- en tekstdelen niet apart tracken.
- Templates gaan in dezelfde aanroep. Er is geen apart template-endpoint: TemplateId of TemplateAlias wordt template (op ID of slug) en TemplateModel wordt template.parameters, op POST /v1/email/messages. Zie verzenden met een template.
- Een message stream heeft geen equivalent, en category is er geen. Een stream is een container met een eigen suppressielijst, eigen statistieken en eigen webhooks. Onze categorie is een per-berichtvlag met één effect: het bepaalt welke suppressierecords en uitschrijfvoorkeuren dat bericht mogen blokkeren. category: transactional instellen omdat een bericht uit een transactionele stream kwam, klopt meestal, maar het is een uitspraak over waarom je verstuurt, niet een port van de stream. Niets hier reproduceert per-streamstatistieken of per-streamsuppressiescoping; gebruik tags voor de rapportagesplitsing.
Suppressies exporteren
Postmark bewaart suppressies per message stream, dus er is geen enkele accountbrede lijst om op te halen. Dump voor elke stream waarop je verstuurt de lijst en verwerk het resultaat via de importloop:
- GET /message-streams/{stream_id}/suppressions/dump
Inventariseer eerst je streams en dump elke stream waarop je nog verstuurt. De standaard outbound-stream als de volledige lijst behandelen neemt de transactionele suppressies mee en mist de broadcastsuppressies, en je komt erachter doordat je mensen mailt die zich hebben afgemeld. De SuppressionReason-waarden zijn HardBounce, SpamComplaint en ManualSuppression, die vertalen naar onze hard_bounce-, complaint- en manual-redenen. Suppressies bevat de volledige taxonomie.
Webhookevents vertalen
Postmark stuurt één webhooktype per event en identificeert het via het RecordType-veld in de payload.
| Resultaat | Postmark | Bird |
|---|---|---|
| Geaccepteerd/verwerkt | (het API-antwoord) | email.accepted → email.processed |
| Afgeleverd | Delivery | email.delivered |
| Tijdelijke fout | Bounce met een tijdelijk Type | email.deferred |
| Permanente bounce | Bounce met Type: HardBounce | email.bounced / email.out_of_band_bounce |
| Spamklacht | SpamComplaint | email.complained |
| Geblokkeerd/onderdrukt | (geen) | email.rejected |
| Open | Open | email.opened |
| Klik | Click | email.clicked |
| Uitschrijving | SubscriptionChange | email.unsubscribed / email.list_unsubscribed |
Twee verschillen bepalen hoeveel je handler verandert.
Verificatie is nieuwe code, geen vervanging. De documentatie van Postmark vermeldt dat het "does not currently support HMAC webhook signature verification" (gelezen september 2026) en raadt HTTP Basic-credentials aan die in de geregistreerde URL zijn ingebed (https://<username>:<password>@example.com/webhook), plus de IP-ranges in je firewall. Wij ondertekenen elke aflevering volgens het Standard Webhooks HMAC-schema, dus je handler krijgt een verificatiestap die hij niet had. Het recept staat in Webhooks en events. Doe deze stap eerst: een handler die niet-ondertekende verzoeken accepteert is het enige dat de migratie niet mag overnemen.
Roteer de credentials in plaats van ze te hergebruiken. Een gebruikersnaam en wachtwoord dat in een webhook-URL heeft gestaan, moet je als blootgesteld beschouwen, omdat URL's in accesslogs, configuratie-exports en een vendorconsole terechtkomen. Haal ze uit het endpoint en geef een nieuw paar uit als iets anders ze nog nodig heeft; neem het oude paar niet mee naar het Bird-endpoint, dat op handtekening authenticeert.
Postmark rapporteert harde en zachte bounces als één Bounce-record met een Type-veld. Wij rapporteren ze als verschillende events. Een handler die op Type vertakt binnen een bouncepayload, vertakt hier op de eventnaam: tijdelijke fouten komen binnen als email.deferred en permanente als email.bounced. Elk bouncetype dat Postmark onderscheidt staat in zijn Bounce API-referentie; wat voor de port telt is aan welke kant van die splitsing elk type valt.
Onze afleverevents zijn per ontvanger (recipient_id naast email_id), dus een verzending aan drie ontvangers levert drie afleverresultaten op in plaats van één.
Cutover
Doorloop domeinen en DNS en de sandbox-rooktest in de hoofdgids. Beide zijn provideronafhankelijk.
Volgende stappen
- Verzenddomeinen: registratie, verificatielevenscyclus en de DNS-records die je publiceert
- Webhooks en events: endpointconfiguratie en Standard Webhooks-verificatie
- Testsandbox: rooktest de nieuwe integratie vóór de cutover
- Suppressies: controleer je geïmporteerde lijst en hoe we die vanaf hier onderhouden
Gerelateerde bronnen
Ga verder met de documentatie, gidsen en voorbeelden voor dit onderwerp. De bronnen zijn in het Engels.
Bekijk de gidsGetting started with emailOntdek de mogelijkheidEmailVolg het leerpadBuild your first integrationImplementatiegidsSend your first email
Probeer de oefening en ontvang een implementatieoverzicht