Novo: campanhas, automações e e-mails do produto na mesma conta. Conheça a Postal
Entrar Criar conta

Migrar da Resend para a Postal

A API da Postal usa os mesmos recursos, nomes de campos e formatos de resposta da API da Resend. Na maioria dos casos, migrar é trocar a URL base e a chave, e o SDK da Resend continua funcionando.

Muda no código
URL e chave
Dá para rodar as duas juntas
Sim
Tempo estimado, mais o DNS
Algumas horas
Tipo de envio
API e SMTP
1

Verifique o domínio na Postal

Cadastre o domínio no painel e crie os registros de DNS que ele mostra. Dá para manter o mesmo domínio na Resend e na Postal ao mesmo tempo: os registros são diferentes, porque a Postal usa o seletor postal no DKIM.

  • A Postal confere os registros sozinha por até 72 horas e avisa por webhook (domain.updated)
  • Se o domínio ainda não tem DMARC, os grandes provedores cobram de quem envia volume: comece com p=none e endureça depois
  • Crie uma chave de API em Chaves de API. Para sistemas que só enviam, use uma chave só de envio, restrita ao domínio
2

Aponte o SDK para a Postal

Os SDKs oficiais da Resend funcionam apontando para a Postal. No Node.js, passe baseUrl ao criar o cliente ou defina RESEND_BASE_URL. O corpo do e-mail, a resposta ({"id"}) e o formato de erro (statusCode, name, message) ficam iguais.

Pelo SDK

Node.js
- const resend = new Resend(process.env.RESEND_API_KEY);+ const resend = new Resend(process.env.POSTAL_API_KEY, { baseUrl: 'https://api.postal.so' });

Ou só pelo ambiente

.env
# Sem mexer no código que já usa new Resend(chave)
RESEND_BASE_URL=https://api.postal.so
RESEND_API_KEY=ps_sua_chave

Por HTTP

cURL
- curl -X POST 'https://api.resend.com/emails' -H 'Authorization: Bearer re_...'+ curl -X POST 'https://api.postal.so/emails' -H 'Authorization: Bearer ps_...'

Por SMTP

SMTP
- Servidor: smtp.resend.com- Usuário: resend- Senha: re_...+ Servidor: smtp.postal.so+ Usuário: postal (resend também é aceito)+ Senha: ps_...

Testado com o pacote resend 6.34 (Node.js): envio simples, agendado, em lote e com idempotência, consulta, edição e cancelamento, anexos, domínios, chaves de API, webhooks e webhooks.verify. Outros SDKs que deixam trocar a URL base falam o mesmo formato, mas não foram testados um a um: se encontrar uma diferença, avise pelo formulário de contato.

3

Importe o que você já tem

Antes de virar o tráfego, leve a lista de supressão, para não escrever a quem já pediu para sair, e os contatos, se você usa a audiência. Recrie também os templates: as variáveis {{{VAR}}} são as mesmas da Resend.

  • Lista de supressão: POST /suppressions/batch/add, com 100 endereços por requisição
  • Contatos: importação por CSV, pelo painel ou pela API
  • Templates: crie e publique com o mesmo alias e as mesmas variáveis; os envios usam sempre a última versão publicada
POST /suppressions/batch/add
curl -X POST https://api.postal.so/suppressions/batch/add \
  -H "Authorization: Bearer $POSTAL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"emails": ["[email protected]", "[email protected]"]}'
4

Recrie o webhook e confira a assinatura

Os nomes dos eventos são os mesmos (email.delivered, email.bounced…), no formato {type, created_at, data}. O que muda é o segredo: na Postal, cada endpoint tem o seu signing_secret (whsec_…). A assinatura segue o padrão Standard Webhooks, e o resend.webhooks.verify aceita os cabeçalhos webhook-* e svix-*.

  • Crie o endpoint em Webhooks (painel ou POST /webhooks) e escolha os eventos
  • Envie um evento de teste pelo painel antes de virar o tráfego
  • São 8 tentativas em cerca de 27 horas, sempre com o mesmo webhook-id; o reenvio manual sai pelo painel ou por POST /webhooks/{id}/events/{event_id}/replay
  • Outras linguagens: veja a verificação da assinatura
Node.js, SDK da Resend
import { Resend } from 'resend';

const resend = new Resend(process.env.POSTAL_API_KEY, { baseUrl: 'https://api.postal.so' });

// Lê o corpo cru da requisição, sem reformatar o JSON
const event = resend.webhooks.verify({
  payload: rawBody,
  headers: {
    id: request.headers['webhook-id'],
    timestamp: request.headers['webhook-timestamp'],
    signature: request.headers['webhook-signature'],
  },
  webhookSecret: process.env.POSTAL_WEBHOOK_SECRET, // whsec_...
});
5

Teste e vire, com as duas por perto

Troque a URL base e a chave no ambiente de testes, mande um e-mail para você mesmo e acompanhe em Logs e nos webhooks. Os endereços de teste aceitam +rótulo, não usam cota, não afetam a reputação e geram webhooks reais (dependem do plano). Depois, vire em produção e deixe a Resend por perto por alguns dias.

  • IDs diferentes. Os IDs de e-mails e de webhooks da Resend não existem na Postal, e o contrário também. Guarde de qual provedor cada e-mail saiu e continue recebendo eventos da Resend para o que saiu por lá
  • Marque a origem. Use tags (por exemplo, provider: postal) e uma Idempotency-Key própria em cada envio
  • Um provedor por vez no mesmo fluxo. Convites, redefinições de senha e códigos devem sair por um só caminho. Olhe os bounces nos primeiros dias, porque o limite de reputação vale para o time inteiro
  • Endereço que voltou a funcionar. Um bounce permanente põe o endereço na lista de supressão; remova com DELETE /suppressions/{id} ou POST /suppressions/batch/remove

O que muda de um para o outro

O que continua igual e o que muda
PontoO que muda na Postal
URL base e chavehttps://api.postal.so e Authorization: Bearer ps_…. Chaves de acesso total ou só de envio, opcionalmente restritas a um domínio.
Envio e respostaPOST /emails, devolve {"id"}. Igual.
Erros{"statusCode", "name", "message"}. Igual. Veja Erros.
Webhooks e assinaturaPadrão Standard Webhooks: webhook-id, webhook-timestamp e webhook-signature, e os mesmos valores em svix-*. O segredo é o signing_secret de cada endpoint.
Nomes dos eventosOs mesmos, mais email.replied, contact.*, form.submitted, broadcast.sent e sending.paused / sending.resumed.
Motivo do bounce e da falhadata.bounce.message e data.failed.reason, com os mesmos campos.
Anexosfilename e content em base64, mais path (URL) e content_id para imagem embutida. Até 40 MB por e-mail; o plano pode permitir menos.
IdempotênciaCabeçalho Idempotency-Key (1 a 256 caracteres, guardado por 24 horas) em POST /emails, /emails/batch e /events.
Agendamentoscheduled_at em ISO 8601, no futuro e a no máximo 30 dias. Dá para reagendar e cancelar.
Limites e cotasCada plano tem as suas requisições por segundo e cotas de envio. Veja Limites e Preços.
Pausa por reputaçãoBounces permanentes acima do limite do nível da reputação da conta (de 3% a 5%), reclamações acima de 0,3% ou conteúdo rejeitado acima de 5% pausam os envios do time: 403 sending_paused. Contas novas começam no nível 1, com teto de 500 e-mails por dia. Antes da pausa, donos e admins recebem um aviso por e-mail.
Regiões de envioSão Paulo (sa-east-1, o padrão), us-east-1, us-east-2, eu-west-1 e ap-northeast-1, por domínio.
CobrançaEm reais, dólares ou euros. A lista pública de planos está em GET /plans.
RetençãoE-mails, eventos de webhook e logs ficam 30 dias; os eventos enviados por POST /events, 90.

O que a Postal acrescenta

  • Região de processamento à sua escolha, com São Paulo como padrão. Como protegemos os dados
  • Inboxes para receber e responder e-mails, com conversas, pastas, etiquetas e rascunhos. Ver Inboxes
  • Audiência e marketing: contatos, segmentos, tópicos, formulários, campanhas e automações, com a mesma chave. Ver o marketing por e-mail
  • Integrações com Stripe, Supabase, Clerk, Auth0 e Firebase, e a CLI postal. Integre seu app

A referência completa está em Migrar da Resend, na documentação.

Antes de virar a chave

  • Domínio verificado na Postal e chave de API guardada no ambiente
  • Lista de supressão e contatos importados
  • Templates recriados e publicados, com as mesmas variáveis
  • Webhook criado e assinatura conferida com um evento de teste
  • Um e-mail de teste enviado e visto em Logs
  • O seu código guarda de qual provedor cada e-mail saiu
  • Bounces conferidos nos primeiros dias depois da virada

Perguntas frequentes

Preciso mudar o código que usa o SDK da Resend?

Em Node.js, só passar baseUrl ao criar o cliente ou definir RESEND_BASE_URL, além de trocar a chave. Outros SDKs que permitem trocar a URL base falam o mesmo formato, mas não foram testados um a um.

Posso manter o mesmo domínio nas duas plataformas?

Sim. Os registros de DNS são diferentes (a Postal usa o seletor postal), então os dois ficam verificados ao mesmo tempo durante a virada.

O código que verifica a assinatura dos webhooks muda?

O resend.webhooks.verify continua servindo, porque a Postal aceita os cabeçalhos webhook-* e svix-*. O que muda é o segredo: use o whsec_… do endpoint criado na Postal.

Os IDs dos meus e-mails continuam valendo?

Não. Os IDs são de cada plataforma. Guarde também de qual provedor cada e-mail saiu, para consultar o status no lugar certo.

Pronto para trocar a URL base?

Crie a sua conta e comece no plano Grátis. Para planejar a cota e a ordem da migração, fale com a gente pelo formulário de contato.