Migrare da Postmark
Questa pagina mappa il payload di invio, le esportazioni di soppressione e i webhook di Postmark su Bird. Segui la guida principale alla migrazione nell'ordine indicato e usa queste corrispondenze per i passaggi 1, 3 e 4.
La documentazione di Postmark dichiara che "does not currently support HMAC webhook signature verification" (consultata a settembre 2026), quindi il passaggio 4 aggiunge una verifica che il tuo handler oggi non ha. Leggi Tradurre gli eventi webhook prima di pianificare il cutover.
Passa questa pagina al tuo agente
Incolla questo prompt in Claude Code, Cursor o Codex. L'agente lavora su questa pagina nel tuo repository, usando qualsiasi superficie Bird già disponibile: il server MCP se è collegato, la CLI se è installata e autenticata.
Esempio di codice
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.Mappare la chiamata di invio
Postmark divide l'invio su due endpoint: POST /email per un messaggio composto e POST /email/withTemplate per un template salvato. Il nostro POST /v1/email/messages è un unico endpoint per entrambi, con il template referenziato in un campo.
| Funzione | Postmark | Bird |
|---|---|---|
| Autenticazione | Header X-Postmark-Server-Token | Authorization: Bearer |
| Mittente | From | from |
| Destinatari | To / Cc / Bcc (separati da virgola, max 50) | to / cc / bcc (array) |
| Oggetto | Subject | subject |
| Corpo | HtmlBody / TextBody | html / text (almeno uno) |
| Reply-to | ReplyTo (separati da virgola) | reply_to (array) |
| Header personalizzati | Headers (oggetti Name/Value) | headers (oggetto string → string) |
| Etichetta filtrabile | Tag (uno per messaggio) | tags: coppie {name, value} |
| Contesto round-trip | Metadata | metadata: JSON arbitrario |
| Template salvato | TemplateId / TemplateAlias + TemplateModel | template + template.parameters |
| Tracciamento aperture | TrackOpens | track_opens (default true) |
| Tracciamento clic | TrackLinks (None/HtmlAndText/HtmlOnly/TextOnly) | track_clicks (booleano, vedi sotto) |
| Allegati | Attachments (Name, Content, ContentType) | attachments |
| Separazione traffico | MessageStream | (nessuna corrispondenza, vedi sotto) |
| Categoria | (nessuna) | category: marketing (default) o transactional |
| Pianificazione | (nessuna) | scheduled_at |
I limiti e i valori predefiniti dei campi (numero di destinatari, limiti di tag e metadati) si trovano in Invio email.
Note sulla migrazione:
- I destinatari sono stringhe in Postmark e array qui. "a@x.com, b@x.com" diventa ["a@x.com", "b@x.com"]. Se il tuo codice costruisce quella stringa unendo una lista, elimina il join invece della lista.
- Tag è una stringa per messaggio. I nostri tags sono coppie, e possono essere più di uno. Un tag come "welcome" diventa {"name": "category", "value": "welcome"}. Scegli un name stabile in modo che le tue dashboard filtrino come facevano le statistiche dei tag su Postmark.
- Metadata si trasferisce direttamente, e lo restituiamo nella risposta. Restituiamo il tuo metadata (e tags) su ogni evento webhook insieme a email_id/recipient_id, così i tuoi handler recuperano il contesto senza bisogno di una ricerca.
- Il tracciamento dei clic è un enum lì e un booleano qui. TrackLinks: "None" corrisponde a track_clicks: false; i tre valori abilitati diventano tutti track_clicks: true, perché non tracciamo le parti HTML e testo separatamente.
- I template passano nella stessa chiamata. Non esiste un endpoint separato per i template: TemplateId o TemplateAlias diventa template (per ID o slug) e TemplateModel diventa template.parameters, su POST /v1/email/messages. Vedi invio con un template.
- Un message stream non ha corrispondenza, e category non lo è. Uno stream è un contenitore con la propria lista di soppressione, le proprie statistiche e i propri webhook. La nostra categoria è un flag per messaggio con un solo effetto: decide quali record di soppressione e preferenze di disiscrizione possono bloccare quel messaggio. Impostare category: transactional perché un messaggio proviene da uno stream transazionale risulta corretto nella maggior parte dei casi, ma è una dichiarazione sul motivo dell'invio, non una trasposizione dello stream. Nulla qui riproduce le statistiche per stream o l'ambito di soppressione per stream; usa i tag per segmentare i report.
Esportare le soppressioni
Postmark conserva le soppressioni per message stream, quindi non esiste un'unica lista a livello di account da estrarre. Per ogni stream su cui invii, esportalo e passa il risultato al ciclo di importazione:
- GET /message-streams/{stream_id}/suppressions/dump
Elenca prima i tuoi stream ed esporta ogni stream su cui invii ancora. Trattare lo stream outbound predefinito come se fosse l'intera lista trascina le soppressioni transazionali e perde quelle broadcast, e te ne accorgi quando scrivi a persone che hanno rinunciato. I valori SuppressionReason sono HardBounce, SpamComplaint e ManualSuppression, che corrispondono ai nostri motivi hard_bounce, complaint e manual. Soppressioni contiene la tassonomia completa.
Tradurre gli eventi webhook
Postmark invia un tipo di webhook per evento e lo identifica tramite il campo RecordType nel payload.
| Esito | Postmark | Bird |
|---|---|---|
| Accettato/elaborato | (la risposta API) | email.accepted → email.processed |
| Consegnato | Delivery | email.delivered |
| Errore temporaneo | Bounce con Type transitorio | email.deferred |
| Bounce permanente | Bounce con Type: HardBounce | email.bounced / email.out_of_band_bounce |
| Segnalazione spam | SpamComplaint | email.complained |
| Bloccato/soppresso | (nessuno) | email.rejected |
| Apertura | Open | email.opened |
| Clic | Click | email.clicked |
| Disiscrizione | SubscriptionChange | email.unsubscribed / email.list_unsubscribed |
Due differenze determinano quanto cambia il tuo handler.
La verifica è codice nuovo, non una sostituzione. La documentazione di Postmark dichiara che "does not currently support HMAC webhook signature verification" (consultata a settembre 2026), e raccomanda credenziali HTTP Basic incorporate nell'URL registrato (https://<username>:<password>@example.com/webhook) più i suoi intervalli IP nel firewall. Noi firmiamo ogni consegna secondo lo schema HMAC di Standard Webhooks, quindi il tuo handler acquisisce un passaggio di verifica che prima non aveva. La procedura è in Webhook ed eventi. Esegui questo passaggio per primo: un handler che accetta richieste non firmate è l'unica cosa che la migrazione non deve portarsi dietro.
Ruota le credenziali invece di riutilizzarle. Un nome utente e una password rimasti dentro un URL di webhook vanno considerati esposti, perché gli URL finiscono nei log di accesso, nelle esportazioni di configurazione e nella console del fornitore. Rimuovili dall'endpoint e genera una nuova coppia se qualcos'altro ne ha ancora bisogno; non trasferire la vecchia coppia sull'endpoint Bird, che si autentica tramite firma.
Postmark segnala hard bounce e soft bounce come un unico record Bounce con un campo Type. Noi li segnaliamo come eventi distinti. Un handler che distingue in base a Type dentro un payload di bounce qui distingue in base al nome dell'evento: gli errori temporanei arrivano come email.deferred e quelli permanenti come email.bounced. Ogni tipo di bounce distinto da Postmark è nel suo riferimento Bounce API; ciò che conta per la migrazione è su quale lato di quella divisione ricade ciascuno.
I nostri eventi di consegna sono per destinatario (recipient_id insieme a email_id), quindi un invio a tre destinatari produce tre esiti di consegna anziché uno.
Cutover
Segui domini e DNS e lo smoke test in sandbox nella guida principale. Entrambi sono indipendenti dal provider.
Passaggi successivi
- Domini di invio: registrazione, ciclo di vita della verifica e record DNS che stai pubblicando
- Webhook ed eventi: configurazione dell'endpoint e verifica Standard Webhooks
- Sandbox di test: smoke test della nuova integrazione prima del cutover
- Soppressioni: verifica della lista importata e come la manteniamo da qui in avanti
Risorse correlate
Prosegui con la documentazione, le guide e gli esempi per questo argomento. Le risorse sono in inglese.
Guarda la guidaGetting started with emailEsplora la funzionalitàEmailSegui il percorso di apprendimentoBuild your first integrationGuida all'implementazioneSend your first email
Prova l'esercitazione e ottieni un brief di implementazione