Do Amazon SES para a Postal, com o SES por baixo
Você já envia pelo SES. Na Postal, a entrega continua sendo do SES, e o que ficava por sua conta passa a vir pronto: domínio guiado, eventos em webhooks, lista de supressão e cuidado com a reputação.
- Para o DNS ser conferido
- Até 72 h
- Os dois funcionam
- API ou SMTP
- Eventos já em webhooks
- Sem SNS
- A região de envio
- Por domínio
Visão geral
O que muda quando o SES fica por baixo
A Postal envia pela conta dela no Amazon SES, e não pela sua. Isso muda quem cuida de cada coisa.
Hoje, direto no SES
- Seu sistemaEnvia com o SDK da AWS ou pelo SMTP do SES.
- Você configura e vigiaIdentidade e DKIM, configuration set, tópico SNS, lista de supressão, cotas e saída do sandbox.
- Amazon SESNa sua conta da AWS.
Com a Postal
- Seu sistemaEnvia pela API ou pelo SMTP da Postal.
- A Postal cuidaDomínio guiado, eventos em webhooks, supressão por time e reputação, com aviso antes de pausar.
- Amazon SESNa conta da Postal, na região que você escolhe para o domínio.
O que passa a ser da Postal
A verificação do domínio, com diagnóstico em português, os eventos em webhooks assinados, a lista de supressão do time (bounces permanentes e reclamações entram sozinhos) e o aviso antes de pausar o envio por reputação.
Ver entregabilidadeO que continua sendo o SES
A entrega em si. Os e-mails saem pela infraestrutura do Amazon SES, e por isso os bounces têm o formato do SES e o Return-Path aponta para feedback-smtp.<região>.amazonses.com.
O que muda na sua conta da AWS
A cota e o sandbox da sua conta deixam de valer para a Postal. Vale o plano: cota por dia e por mês, limite de requisições e pausa por reputação. A sua conta pode ficar como está até você desligar o último envio.
Ver limitesA documentação da Postal não trata de IPs dedicados do SES. Se a sua conta usa IPs dedicados, fale com a gente pelo formulário de contato antes de migrar.
Faça o inventário no SES
Antes de mudar qualquer coisa, liste o que o seu sistema usa no SES. Cada item tem um lugar na Postal. As identidades do SES valem para uma região só, então anote as regiões em que você envia.
| No console do SES | O que anotar | Onde fica na Postal |
|---|---|---|
| Identities | Domínios e endereços verificados, e a região de cada um | Domínios (a região é escolhida por domínio) |
| Configuration sets | Nomes e destinos de evento | Webhooks, e o rastreamento de abertura e clique no domínio |
| Email templates | Nome do modelo e as variáveis | Templates |
| Tópicos do SNS | Quem assina e que código recebe os eventos | Webhooks |
| Suppression list | Endereços suprimidos, por região | Supressões |
| SMTP settings | Quem usa as credenciais SMTP | Chaves de API |
Verifique o domínio na Postal
Adicione o domínio em Domínios (ou com POST /domains), escolha a região e publique os registros que a Postal mostra. Ela confere o DNS sozinha por até 72 horas, mostra o status de cada registro e explica o que está errado. O domínio pode continuar verificado no SES ao mesmo tempo: os nomes dos registros são diferentes.
| No SES | Na Postal | |
|---|---|---|
| DKIM | 3 registros CNAME, <token>._domainkey, apontando para <token>.dkim.<região>.amazonses.com (Easy DKIM) | 1 registro TXT, postal._domainkey, com a chave pública da Postal |
| Return-Path (MAIL FROM) | Opcional. Um subdomínio seu, com MX 10 feedback-smtp.<região>.amazonses.com e TXT "v=spf1 include:amazonses.com ~all" | O subdomínio postal (muda com custom_return_path): MX para feedback-smtp.<região>.amazonses.com e TXT v=spf1 include:_spf.postal.so ~all |
| SPF do domínio principal | Seu, se você incluiu amazonses.com | Não muda: o SPF da Postal fica no subdomínio do Return-Path |
| DMARC | Seu | Continua valendo. A Postal não exige, mas os grandes provedores cobram de quem envia volume |
| Região | Uma identidade por região | Uma região por domínio: São Paulo (padrão), Virgínia do Norte, Ohio, Irlanda ou Tóquio |
| Prazo | Até 72 horas para o DNS propagar | Até 72 horas, com diagnóstico em português por registro |
- Se o seu Return-Path no SES já se chama
postal, escolha outro nome na Postal comcustom_return_path, para não misturar os registros. - Para migrar aos poucos, use um subdomínio só de e-mail, como
mail.exemplo.com.br. - A Postal avisa pelo webhook
domain.updatedquando o domínio viraverified. Veja Domínios e DNS.
Troque a chamada do SDK pela API
Crie uma chave de API (acesso total, ou só de envio e restrita ao domínio) e troque o SendEmail do SDK da AWS por POST /emails. A resposta traz o id do e-mail, no lugar do MessageId.
- import { SESv2Client, SendEmailCommand } from '@aws-sdk/client-sesv2'- - const ses = new SESv2Client({ region: 'us-east-1' })- await ses.send(new SendEmailCommand({- FromEmailAddress: 'Aurora Cosméticos <[email protected]>',- Destination: { ToAddresses: ['[email protected]'] },- Content: { Simple: {- Subject: { Data: 'Seu pedido saiu para entrega' },- Body: { Html: { Data: '<p>O pedido #10482 está a caminho.</p>' } },- } },- EmailTags: [{ Name: 'category', Value: 'shipping' }],- }))+ await fetch('https://api.postal.so/emails', {+ method: 'POST',+ headers: {+ Authorization: `Bearer ${process.env.POSTAL_API_KEY}`,+ 'Content-Type': 'application/json',+ },+ body: JSON.stringify({+ from: 'Aurora Cosméticos <[email protected]>',+ to: ['[email protected]'],+ subject: 'Seu pedido saiu para entrega',+ html: '<p>O pedido #10482 está a caminho.</p>',+ tags: [{ name: 'category', value: 'shipping' }],+ }),+ })| Campo no SES (SendEmail, v2) | Na Postal | O que muda |
|---|---|---|
FromEmailAddress | from | O domínio precisa estar verificado na Postal. |
Destination.ToAddresses | to | Texto ou lista, com até 50 destinatários. |
CcAddresses, BccAddresses | cc, bcc | Iguais. |
ReplyToAddresses | reply_to | Texto ou lista. |
Content.Simple (Subject, Body.Html, Body.Text) | subject, html, text | Sem os objetos Data e Charset: é o texto direto. |
Content.Simple.Headers | headers | Um objeto nome → valor. Alguns nomes não podem ser trocados (From, To, Subject...). |
Content.Simple.Attachments | attachments | filename e content em base64, ou path com uma URL. Até 40 MB no total. O content_id serve para imagem embutida. |
Content.Template (TemplateName, TemplateData) | template (id ou alias, variables) | As variáveis passam de {{nome}} para {{{NOME}}}. Só texto e número: listas e objetos aninhados precisam ser resolvidos antes de enviar. |
Content.Raw | Sem campo na API | Use o SMTP da Postal, que entrega a mensagem como ela chegou. |
EmailTags (Name, Value) | tags (name, value) | Letras ASCII, números, _ e -. Até 50 por e-mail. |
ConfigurationSetName | Não precisa | Os eventos vão para webhooks. |
ConfigurationOverrides.Tracking | open_tracking, click_tracking | Ficam ligados no domínio, não em cada mensagem. |
FeedbackForwardingEmailAddress | Não precisa | Bounces e reclamações viram eventos e entram na supressão. O Return-Path é da Postal. |
SendBulkEmail | POST /emails/batch | Uma lista de até 100 e-mails (no SES, até 50 destinos). Sem anexos nem scheduled_at, e depende do plano. |
| Não existe | scheduled_at, Idempotency-Key | Novos: agendar até 30 dias (depende do plano) e repetir uma chamada sem duplicar o envio, por 24 horas. |
- Os erros chegam com o status HTTP e um JSON
{statusCode, name, message}. A cota responde429e a pausa por reputação,403 sending_paused. - Prefere um SDK? Os da Postal (Node.js, PHP e Laravel) e o da Resend, apontado para a Postal, usam a mesma API. Veja SDKs e CLI e a referência de e-mails.
Se você envia por SMTP, troque só o servidor
Sistemas que falam SMTP, como WordPress, ERPs e plataformas de loja, mudam quatro campos: servidor, porta, usuário e senha. A senha deixa de ser a senha SMTP derivada de uma chave do IAM e passa a ser uma chave de API da Postal.
- MAIL_HOST=email-smtp.us-east-1.amazonaws.com- MAIL_PORT=587- MAIL_USERNAME=<usuário SMTP do SES>- MAIL_PASSWORD=<senha SMTP do SES>+ MAIL_HOST=smtp.postal.so+ MAIL_PORT=587+ MAIL_USERNAME=postal+ MAIL_PASSWORD=ps_sua_chave| SMTP do SES | SMTP da Postal | |
|---|---|---|
| Servidor | email-smtp.<região>.amazonaws.com | smtp.postal.so |
| Portas com STARTTLS | 25, 587 ou 2587 | 587 ou 2587 |
| Portas com TLS direto | 465 ou 2465 | 465 (recomendada) ou 2465 |
| Usuário | O usuário SMTP gerado no SES, um par por região | postal |
| Senha | A senha SMTP, que não é a chave secreta da AWS | Uma chave de API (ps_…). Uma chave só de envio basta |
| Remetente | Uma identidade verificada no SES | Um domínio verificado na Postal |
- O TLS é obrigatório nos dois. Na Postal, a autenticação (
AUTH PLAINouAUTH LOGIN) vem sempre depois do TLS. - O SMTP da Postal não tem etiquetas, agendamento nem templates: para isso, use a API. Se o seu sistema manda os cabeçalhos
X-SES-CONFIGURATION-SETouX-SES-MESSAGE-TAGS, tire-os, porque são do SES. - Os envios por SMTP seguem as mesmas regras da API (domínio verificado, cotas e supressão) e aparecem em E-mails e Logs. Cada mensagem aceita pode ter até 40 MB e 50 destinatários. Veja o guia de SMTP.
Troque o SNS pelos webhooks
No SES, o caminho dos eventos é seu: configuration set, destino de evento, tópico SNS e uma assinatura que o seu código precisa receber. Na Postal você cadastra uma URL HTTPS em Webhooks e escolhe os eventos. Cada entrega é assinada com o signing_secret do endpoint e repetida se falhar.
- const message = JSON.parse(body.Message)- if (message.eventType === 'Bounce') {- const kind = message.bounce.bounceType- const id = message.mail.messageId- }+ const event = resend.webhooks.verify({ payload: rawBody, headers, webhookSecret })+ if (event.type === 'email.bounced') {+ const kind = event.data.bounce.type+ const id = event.data.email_id+ }| Evento no SES (eventType) | Evento na Postal | Observação |
|---|---|---|
Send | email.sent | A Postal entregou o e-mail ao provedor de envio. |
Delivery | email.delivered | O servidor do destinatário aceitou a mensagem. |
DeliveryDelay | email.delivery_delayed | As novas tentativas acontecem sozinhas. |
Bounce | email.bounced | data.bounce traz type (Permanent, Transient ou Undetermined), subType e diagnosticCode. Bounce permanente põe o endereço na supressão. |
Complaint | email.complained | O endereço entra na lista de supressão. |
Open, Click | email.opened, email.clicked | Ligue open_tracking e click_tracking no domínio. |
Rendering Failure | Não existe | Uma variável de template sem valor devolve 422 na hora do envio. |
Subscription (listas de contatos do SES) | contact.updated | Vale para a audiência e as campanhas da Postal. |
- O identificador que você guarda passa a ser o
iddevolvido porPOST /emails(data.email_idno webhook), e não oMessageIddo SES. - As etiquetas voltam em
data.tagscomo objeto, por exemplo{"category": "shipping"}. - A Postal tem ainda eventos que o SES não tem, como
email.scheduled,email.suppressed,email.receivededomain.updated. - Qualquer resposta 2xx confirma a entrega. Tire o tópico SNS só depois de virar todo o tráfego, porque os e-mails que ainda saem pelo SES continuam gerando eventos lá. Veja Webhooks.
Leve a lista de supressão do SES
Quem já deu bounce permanente ou reclamou no SES não deve receber de novo. Exporte a lista de supressão da sua conta e importe na Postal antes do primeiro envio e antes de importar contatos, porque um endereço suprimido nunca vira contato.
aws sesv2 list-suppressed-destinations --region us-east-1 > supressoes-ses.json
# se a resposta trouxer "NextToken", repita com --next-token "<valor>"
jq -r '.SuppressedDestinationSummaries[].EmailAddress' supressoes-ses.json \
| tr 'A-Z' 'a-z' | sort -u > emails.txtimport { readFileSync } from 'node:fs'
const emails = readFileSync('emails.txt', 'utf8').split('\n').filter(Boolean)
const headers = {
Authorization: `Bearer ${process.env.POSTAL_API_KEY}`,
'Content-Type': 'application/json',
}
for (let i = 0; i < emails.length; i += 100) {
const res = await fetch('https://api.postal.so/suppressions/batch/add', {
method: 'POST',
headers,
body: JSON.stringify({ emails: emails.slice(i, i + 100) }),
})
if (!res.ok) throw new Error(await res.text())
await new Promise((resolve) => setTimeout(resolve, 250)) // respeita o limite do plano
}- A lista do SES vale para a conta e para a região. Exporte uma vez por região em que você enviava. No console, ela fica em Configuration > Suppression list.
- O SES guarda o endereço exatamente como entrou, com maiúsculas e minúsculas. A Postal compara sem diferenciar, então o comando acima passa tudo para minúsculas e tira os repetidos.
- Na Postal, os endereços entram com a origem
manual: a diferença entreBOUNCEeCOMPLAINTdo SES não é guardada. - Precisa de uma chave de acesso total. Para poucos endereços, o painel aceita um por vez em Supressões. Veja a referência de supressões.
Confira as cotas e vire o tráfego
Vire um fluxo de cada vez. Comece pelos endereços de teste e por você mesmo, acompanhe em E-mails e Logs e só então passe o resto. Mantenha o SES ligado até os eventos dos últimos e-mails antigos chegarem.
| No SES | Na Postal | |
|---|---|---|
| Taxa de envio | O limite de envio da sua conta, por região | Requisições por segundo, por time: Grátis 5, Profissional 10, Escala 20, Empresarial 50. No lote, 100 e-mails contam como uma requisição |
| Cota de envio | A da sua conta, por região | Por plano. Grátis: 100 por dia e 3.000 por mês. Profissional: 50.000 por mês. Escala: 100.000 por mês. Empresarial: sob medida. O limite por dia também segue a reputação da conta: contas novas começam com 500 |
| Sandbox | Até pedir acesso de produção: 200 mensagens por 24 horas, 1 por segundo, só para endereços verificados | Você não pede saída do sandbox na AWS. O limite é a cota do plano |
| Reputação | Da sua conta | Do time, de 0 a 100 pontos, começando em 0. O envio pausa quando os bounces permanentes passam do limite do nível (de 3% a 5%) ou as reclamações de 0,3%. Antes disso, donos e admins recebem um aviso |
- Os endereços de teste (
delivered@,bounced@,complained@,suppressed@e[email protected]) não usam a cota nem pesam na reputação. Dependem do plano. - Veja os valores atuais em Preços e em Limites.
Antes de virar a chave
- O domínio está
verifiedna Postal e o DMARC está em ordem. - A chave de API foi criada (só envio e restrita ao domínio, nos sistemas que apenas enviam).
- Um e-mail de teste chegou e os cabeçalhos mostram DKIM e SPF do seu domínio.
- O webhook está cadastrado e o seu código confere a assinatura.
- A lista de supressão do SES, de todas as regiões, já foi importada.
- Cabeçalhos
X-SES-*e tópicos SNS que não servem mais foram identificados. - A cota do plano e o limite de requisições cobrem o seu volume diário.
- Donos e admins do time sabem o que fazer se o envio pausar por reputação.
Perguntas frequentes
Preciso manter a minha conta da AWS?
Para enviar pela Postal, não: ela usa a conta dela no SES. Mantenha a sua enquanto algum sistema ainda enviar por lá e até chegarem os eventos dos últimos e-mails. Depois, se quiser, apague as identidades e os registros de DNS do SES que não usa mais.
O meu domínio já está verificado no SES. Posso verificar na Postal também?
Pode. O DKIM da Postal usa o seletor postal e o Return-Path fica num subdomínio próprio, então os registros não colidem com os do SES, e o SPF do domínio principal não muda. A exceção é um Return-Path seu que já se chame postal: use outro nome com custom_return_path.
O que acontece com a reputação de envio?
Ela passa a ser medida por time, com a reputação da conta: uma pontuação que começa em 0 e sobe a cada dia de envios sem problemas. Contas novas começam com um teto de 500 e-mails por dia, que cresce com o nível. A Postal pausa o envio se os bounces permanentes passarem do limite do nível (de 3% a 5%) ou as reclamações de 0,3%. Importar a lista de supressão do SES ajuda a não repetir bounces já conhecidos.
Posso usar IPs dedicados?
A documentação da Postal não trata disso. Se a sua conta do SES usa IPs dedicados, fale com a gente pelo formulário de contato antes de migrar.
Continue por aqui
E-mail transacional
API, SMTP, webhooks e inboxes para o e-mail que sai do seu sistema.
Saiba maisWebhooks e eventos
Cada evento de e-mail no seu servidor, com assinatura e novas tentativas.
Saiba maisLista de supressão
Quem não deve receber fica protegido, por time.
Saiba maisOutros guias de migração