Sign inGet started

Migrar do Postmark

Esta página mapeia o payload de envio, os dumps de supressão e os webhooks do Postmark para Bird. Siga o guia principal de migração na ordem e use esses mapeamentos para os passos 1, 3 e 4.
A documentação do Postmark afirma que ele "does not currently support HMAC webhook signature verification" (lido em setembro de 2026), então o passo 4 adiciona verificação que o seu handler não tem hoje. Leia Traduzir eventos de webhook antes de planejar a virada.

Passe isto para o seu agente

Cole isto no Claude Code, Cursor ou Codex. O agente percorre esta página no seu próprio repositório, usando qualquer superfície Bird que já tenha: o servidor MCP se estiver conectado, o CLI se estiver instalado e autenticado.
Exemplo de código
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.

Mapear a chamada de envio

O Postmark divide o envio em dois endpoints: POST /email para uma mensagem composta e POST /email/withTemplate para um template armazenado. Nosso POST /v1/email/messages é um único endpoint para ambos, com o template referenciado em um campo.
O que fazPostmarkBird
AutenticaçãoHeader X-Postmark-Server-TokenAuthorization: Bearer
RemetenteFromfrom
DestinatáriosTo / Cc / Bcc (separados por vírgula, máx. 50)to / cc / bcc (arrays)
AssuntoSubjectsubject
CorpoHtmlBody / TextBodyhtml / text (pelo menos um)
Reply-toReplyTo (separados por vírgula)reply_to (array)
Headers personalizadosHeaders (objetos Name/Value)headers (objeto string → string)
Rótulo filtrávelTag (um por mensagem)tags: pares {name, value}
Contexto de ida e voltaMetadatametadata: JSON arbitrário
Template armazenadoTemplateId / TemplateAlias + TemplateModeltemplate + template.parameters
Rastreamento de aberturaTrackOpenstrack_opens (padrão true)
Rastreamento de cliqueTrackLinks (None/HtmlAndText/HtmlOnly/TextOnly)track_clicks (booleano, veja abaixo)
AnexosAttachments (Name, Content, ContentType)attachments
Separação de tráfegoMessageStream(sem equivalente, veja abaixo)
Categoria(nenhum)category: marketing (padrão) ou transactional
Agendamento(nenhum)scheduled_at
Nossos limites e valores padrão de campos (contagem de destinatários, limites de tags e metadados) estão em Enviando e-mail.
Notas de portabilidade:
  • Destinatários são strings no Postmark e arrays aqui. "a@x.com, b@x.com" se torna ["a@x.com", "b@x.com"]. Se o seu código monta essa string juntando uma lista, remova o join em vez da lista.
  • Tag é uma string por mensagem. Nossas tags são pares, e pode haver várias. Uma tag como "welcome" se torna {"name": "category", "value": "welcome"}. Escolha um name estável para que seus dashboards filtrem da mesma forma que as estatísticas de tag do Postmark faziam.
  • Metadata é portado diretamente, e nós o devolvemos. Retornamos seu metadata (e tags) em cada evento de webhook junto com email_id/recipient_id, para que seus handlers recuperem o contexto sem precisar de consulta.
  • Rastreamento de clique é um enum lá e um booleano aqui. TrackLinks: "None" é track_clicks: false; os três valores habilitados se tornam track_clicks: true, porque não rastreamos as partes HTML e texto separadamente.
  • Templates passam para a mesma chamada. Não há endpoint separado para templates: TemplateId ou TemplateAlias se torna template (por ID ou slug) e TemplateModel se torna template.parameters, em POST /v1/email/messages. Veja enviando com template.
  • Um message stream não tem equivalente, e category não é um. Um stream é um contêiner com sua própria lista de supressão, suas próprias estatísticas e seus próprios webhooks. Nossa categoria é um flag por mensagem com um único efeito: ela decide quais registros de supressão e preferências de cancelamento podem bloquear aquela mensagem. Definir category: transactional porque a mensagem veio de um stream transacional costuma estar correto na maioria das vezes, mas é uma declaração sobre o motivo do envio, não uma portabilidade do stream. Nada aqui reproduz estatísticas por stream ou escopo de supressão por stream; use tags para a divisão de relatórios.

Exportar supressões

O Postmark mantém supressões por message stream, então não existe uma lista única de toda a conta para extrair. Para cada stream em que você envia, exporte-o e passe o resultado pelo loop de importação:
  • GET /message-streams/{stream_id}/suppressions/dump
Enumere seus streams primeiro e exporte cada um em que você ainda envia. Tratar o stream outbound padrão como se fosse a lista carrega as supressões transacionais e perde as de broadcast, e você descobre isso enviando e-mails para pessoas que cancelaram a inscrição. Os valores de SuppressionReason são HardBounce, SpamComplaint e ManualSuppression, que mapeiam para nossos motivos hard_bounce, complaint e manual. Supressões contém a taxonomia completa.

Traduzir eventos de webhook

O Postmark envia um tipo de webhook por evento e o identifica pelo campo RecordType no payload.
ResultadoPostmarkBird
Aceito/processado(a resposta do API)email.acceptedemail.processed
EntregueDeliveryemail.delivered
Falha temporáriaBounce com Type transienteemail.deferred
Bounce permanenteBounce com Type: HardBounceemail.bounced / email.out_of_band_bounce
Reclamação de spamSpamComplaintemail.complained
Bloqueado/suprimido(nenhum)email.rejected
AberturaOpenemail.opened
CliqueClickemail.clicked
CancelamentoSubscriptionChangeemail.unsubscribed / email.list_unsubscribed
Duas diferenças determinam o quanto o seu handler muda.
A verificação é código novo, não uma troca. A documentação do Postmark afirma que ele "does not currently support HMAC webhook signature verification" (lido em setembro de 2026), e recomenda credenciais HTTP Basic embutidas na URL registrada (https://<username>:<password>@example.com/webhook) mais seus intervalos de IP no seu firewall. Nós assinamos cada entrega conforme o esquema HMAC do Standard Webhooks, então o seu handler ganha um passo de verificação que não tinha. A receita está em Webhooks e eventos. Faça este passo primeiro: um handler que aceita solicitações não assinadas é a única coisa que a migração não deve trazer.
Rotacione as credenciais em vez de reutilizá-las. Um nome de usuário e senha que viveu dentro de uma URL de webhook deve ser tratado como exposto, porque URLs chegam a logs de acesso, exportações de configuração e um console de fornecedor. Remova-os do endpoint e emita um novo par se algo mais ainda precisar deles; não carregue o par antigo para o endpoint Bird, que autentica por assinatura.
O Postmark reporta hard e soft bounces como um único registro Bounce com um campo Type. Nós os reportamos como eventos diferentes. Um handler que ramifica por Type dentro de um payload de bounce ramifica pelo nome do evento aqui: falhas transientes chegam como email.deferred e permanentes como email.bounced. Cada tipo de bounce que o Postmark distingue está na referência Bounce API; o que importa para a portabilidade é de que lado dessa divisão cada um cai.
Nossos eventos de entrega são por destinatário (recipient_id junto com email_id), então um envio para três destinatários produz três resultados de entrega em vez de um.

Virada

Siga domínios e DNS e o teste de fumaça no sandbox no guia principal. Ambos são independentes de provedor.

Próximos passos

  • Domínios de envio: registro, ciclo de vida de verificação e os registros DNS que você está publicando
  • Webhooks e eventos: configuração de endpoint e verificação Standard Webhooks
  • Sandbox de testes: teste a nova integração antes da virada
  • Supressões: confirme sua lista importada e como a mantemos daqui em diante