Email Transacional no seu App feito com IA: Como Enviar com Resend e Supabase [2026]
![Email Transacional no seu App feito com IA: Como Enviar com Resend e Supabase [2026]](/_next/image?url=https%3A%2F%2Ffxomitcagluilpagghdp.supabase.co%2Fstorage%2Fv1%2Fobject%2Fpublic%2Farticle-images%2Fcovers%2F1790239941399-dtl5iomba8q.png&w=1920&q=75)
TL;DR
- O SMTP padrão do Supabase serve só para testes, então todo app em produção precisa de um provedor de email transacional configurado como SMTP customizado.
Levar para a IA
Leve este artigo para o ChatGPT, o Claude ou a sua IA preferida.
Seu app feito com IA está no ar, o primeiro usuário se cadastra e o email de confirmação nunca chega. Essa cena acontece com quase todo mundo que sai do protótipo para a produção, e o motivo quase sempre é o mesmo: ninguém configurou o email transacional. Pedir uma tela de login para a IA é fácil. Garantir que o link de confirmação, o reset de senha e o recibo de pagamento cheguem na caixa de entrada é outra etapa, e ela fica de fora da maioria dos tutoriais.
Na Marfin, todo projeto que sai de uma sessão de vibe coding passa pela mesma checklist antes de receber usuários reais, e email é um dos primeiros itens. O combo que usamos na maioria dos casos é Supabase no backend e Resend no envio. É simples de configurar, barato no começo e aguenta o crescimento sem trocar de ferramenta.
Neste guia mostramos o caminho completo: o que é email transacional, por que o SMTP padrão do Supabase não aguenta produção, como configurar domínio e DNS no Resend, como ligar o SMTP customizado no Supabase Auth, como enviar emails do produto com Edge Functions, como montar templates com React Email e como pedir tudo isso para Claude Code ou Cursor sem perder o controle do que está sendo feito.
O que é email transacional
Email transacional é a mensagem que o sistema dispara porque o usuário fez alguma coisa. Cadastro, confirmação de email, redefinição de senha, magic link, recibo de compra, convite para um workspace, alerta de login num dispositivo novo, aviso de que o cartão foi recusado. Cada um desses emails tem um destinatário, um gatilho e uma expectativa de chegada em segundos.
A diferença para o email marketing está no gatilho e na permissão. Uma newsletter ou campanha sai para uma lista, num horário escolhido pela equipe, e o usuário pode se descadastrar a qualquer momento. O email transacional sai para uma pessoa, na hora em que ela precisa, e faz parte do funcionamento do produto. Se o link de reset de senha não chega, o usuário fica trancado para fora da conta. Se o recibo não chega, o suporte recebe um ticket. Por isso os provedores tratam os dois tipos de envio de forma diferente, e por isso vale separar os dois na sua infraestrutura desde o primeiro dia.
Na prática, um SaaS pequeno manda três famílias de email transacional. A primeira é a de autenticação, que o Supabase Auth dispara sozinho: confirmação de cadastro, magic link, reset de senha, troca de email e convite. A segunda é a de produto, que o seu código dispara: boas-vindas, notificação de atividade, relatório semanal, convite para colaborar. A terceira é a de cobrança, que costuma vir do Stripe ou do gateway de pagamento, mas que muitos apps preferem personalizar. Se você está montando um produto por assinatura, vale ler nosso guia sobre o que é SaaS para entender onde cada um desses emails entra na jornada do cliente.
Por que o SMTP padrão do Supabase não serve para produção
Todo projeto Supabase vem com um servidor de email embutido. Ele existe para você testar o fluxo de autenticação sem configurar nada, e é aí que muita gente para. O problema aparece no primeiro dia com usuários reais.
O SMTP padrão tem um limite de envios por hora muito baixo, pensado para desenvolvimento. Ele também só entrega para endereços que fazem parte da equipe da organização no Supabase, então o seu primeiro cliente de verdade simplesmente não recebe nada. O remetente é um endereço genérico do Supabase, sem a sua marca, o que derruba a taxa de abertura e aumenta a chance de a mensagem ir para o spam. E você não tem nenhum controle sobre reputação, logs de entrega ou bounces.
A própria documentação do Supabase deixa claro que, para produção, o caminho é configurar um SMTP customizado. É uma tela no painel, cinco campos, e resolve o problema de autenticação de uma vez. Os emails de produto ficam para a segunda etapa, com Edge Functions. Se você ainda está conhecendo a plataforma, nosso tutorial de Supabase cobre banco, Auth, RLS e Storage antes de chegar nessa parte.
Resend: o provedor de email transacional que usamos com Supabase
O Resend é um provedor de email feito para desenvolvedores. A API tem um endpoint principal, o SDK funciona em Node, Deno, Python, Go e outras linguagens, e o painel mostra cada email enviado com status de entrega, abertura e bounce. A equipe por trás dele também criou o React Email, uma biblioteca para montar templates de email com componentes React, o que encaixa bem em projetos Next.js.
Escolhemos o Resend como padrão por três motivos. O primeiro é a velocidade de configuração: do cadastro ao primeiro email saindo do seu domínio leva uns vinte minutos, contando o tempo de propagação do DNS. O segundo é que os modelos de IA conhecem bem a API, então Claude Code e Cursor geram integrações corretas de primeira na grande maioria das vezes. O terceiro é o plano gratuito, que cobre a fase de validação de quase qualquer produto.
Configurando domínio e DNS: SPF, DKIM e DMARC
Antes de enviar qualquer coisa, você precisa verificar um domínio no Resend. A nossa recomendação é usar um subdomínio dedicado, como mail.seuapp.com.br ou send.seuapp.com.br. Isso isola a reputação do email transacional do email corporativo da equipe. Se algum dia um envio mal configurado gerar reclamações de spam, o Google Workspace da sua empresa continua intacto.
No painel do Resend, você adiciona o domínio e ele gera os registros DNS que precisam ser criados no seu provedor (Cloudflare, Registro.br, Route 53, Vercel ou onde estiver o DNS). São basicamente três tipos de registro.
O SPF é um registro TXT que diz quais servidores podem enviar email em nome do seu domínio. O Resend usa um registro MX e um TXT no subdomínio de retorno para isso. O DKIM é uma assinatura criptográfica: o Resend assina cada email com uma chave privada e publica a chave pública num registro TXT, e o servidor de destino confere se a mensagem não foi adulterada no caminho. O DMARC é a política que diz aos provedores o que fazer quando SPF ou DKIM falham, e onde mandar relatórios.
Desde 2024, Gmail e Yahoo exigem SPF, DKIM e DMARC configurados para remetentes com volume relevante, e na prática aplicam filtros mais duros para qualquer remetente sem esses registros. Um DMARC inicial simples já resolve:
_dmarc.seuapp.com.br TXT "v=DMARC1; p=none; rua=mailto:dmarc@seuapp.com.br"
Com p=none você só monitora. Depois de algumas semanas sem problemas nos relatórios, dá para subir para p=quarantine e mais tarde p=reject. Assim que os registros propagarem, o Resend marca o domínio como verificado e você pode enviar.
Passo 1: SMTP customizado no Supabase Auth
Com o domínio verificado, crie uma API key no Resend com permissão de envio. Depois abra o painel do Supabase, vá em Authentication, depois em Emails (ou SMTP Settings, dependendo da versão do painel), e ative o SMTP customizado.
Os campos ficam assim. Host: smtp.resend.com. Porta: 465. Usuário: resend. Senha: a sua API key, que começa com re_. Remetente: algo como nao-responda@mail.seuapp.com.br. Nome do remetente: o nome do seu produto, porque é isso que aparece na caixa de entrada do usuário.
Salvou, e a partir daí todos os emails de autenticação do Supabase saem pelo Resend, com o seu domínio. Aproveite para ajustar o limite de envios por hora na seção de rate limits do Auth, porque o padrão continua conservador mesmo com SMTP próprio. Para um app em lançamento, algo entre 100 e 300 emails por hora costuma ser suficiente, e você ajusta conforme o tráfego.
Na mesma área ficam os templates de autenticação. O Supabase usa variáveis como {{ .ConfirmationURL }}, {{ .Token }} e {{ .SiteURL }}. Traduza todos para português, coloque a sua marca e revise o assunto de cada um. Um assunto como "Confirme seu cadastro no Seu App" tem taxa de abertura bem maior do que o padrão em inglês. Confira também a Site URL e as Redirect URLs nas configurações de URL do Auth, porque link de confirmação apontando para localhost é um dos erros mais comuns que vemos em apps recém-publicados.
Se o seu app precisa de um controle ainda maior, o Supabase tem o Send Email Hook, que substitui o envio padrão por uma função sua. Com ele, você recebe o evento de autenticação e decide como montar e enviar o email, inclusive com templates React Email. Para a maioria dos projetos, o SMTP customizado com templates editados no painel dá conta.
Passo 2: enviando emails do produto com Edge Functions
Os emails de autenticação estão resolvidos. Agora vêm os emails que o seu produto dispara: boas-vindas depois do onboarding, aviso de que alguém comentou no seu projeto, relatório semanal. Esses saem do seu código, e no Supabase o lugar natural para isso é uma Edge Function.
Edge Functions rodam em Deno, perto do banco, e guardam segredos com segurança. A API key do Resend nunca pode ficar no frontend. Se ela aparecer no bundle do navegador, qualquer pessoa pode usar o seu domínio para mandar spam, e a sua reputação de envio vai embora em horas.
Primeiro, salve a chave como segredo do projeto:
supabase secrets set RESEND_API_KEY=re_sua_chave_aqui
Depois crie a função. Este exemplo recebe o ID de um usuário e um tipo de email, busca o endereço no banco e monta a mensagem do lado do servidor:
// supabase/functions/send-email/index.ts
import { createClient } from "npm:@supabase/supabase-js@2";
const RESEND_API_KEY = Deno.env.get("RESEND_API_KEY")!;
const supabase = createClient(
Deno.env.get("SUPABASE_URL")!,
Deno.env.get("SUPABASE_SERVICE_ROLE_KEY")!,
);
const templates = {
welcome: (name: string) => ({
subject: "Bem-vindo ao Seu App",
html: `<p>Oi, ${name}! Sua conta está pronta.</p>`,
}),
};
Deno.serve(async (req) => {
const { userId, type } = await req.json();
const template = templates[type as keyof typeof templates];
if (!template) return new Response("tipo inválido", { status: 400 });
const { data: profile, error } = await supabase
.from("profiles")
.select("email, name")
.eq("id", userId)
.single();
if (error || !profile) return new Response("usuário não encontrado", { status: 404 });
const { subject, html } = template(profile.name ?? "");
const res = await fetch("https://api.resend.com/emails", {
method: "POST",
headers: {
Authorization: `Bearer ${RESEND_API_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": `${type}-${userId}`,
},
body: JSON.stringify({
from: "Seu App <nao-responda@mail.seuapp.com.br>",
to: profile.email,
subject,
html,
}),
});
return new Response(await res.text(), { status: res.status });
});
E faça o deploy:
supabase functions deploy send-email
Dois detalhes desse código fazem diferença em produção. O primeiro é que a função recebe um ID e um tipo, e o endereço vem do banco. Se a função aceitasse to e html livres vindos do cliente, qualquer usuário logado poderia mandar qualquer conteúdo para qualquer endereço usando o seu domínio. O segundo é o header Idempotency-Key: se a função for chamada duas vezes para o mesmo evento, por retry de rede ou por clique duplo, o Resend entrega um email só.
Por padrão, Edge Functions exigem um JWT válido, então só usuários autenticados conseguem chamar a função. Se ela for disparada apenas pelo banco ou por outro serviço interno, vale restringir ainda mais e validar um segredo compartilhado no header.
Disparando email a partir do banco com Database Webhooks
Chamar a função pelo frontend funciona, mas o padrão mais robusto é disparar pelo banco. O Supabase tem Database Webhooks, que chamam uma URL sempre que uma linha é inserida, atualizada ou removida numa tabela. Você configura um webhook na tabela profiles para o evento de INSERT, apontando para a Edge Function, e o email de boas-vindas sai sozinho sempre que um perfil novo é criado.
A vantagem é que o email fica amarrado ao dado. Não importa se o perfil foi criado pelo app web, pelo app mobile ou por um script de importação: o email sai do mesmo jeito. Para tarefas agendadas, como o relatório semanal, o pg_cron do Supabase chama a função no horário definido.
Quando o fluxo começa a envolver várias etapas fora do banco, como esperar dois dias, checar se o usuário ativou uma feature e só então mandar um lembrete, algumas equipes preferem uma ferramenta de automação visual. Na Marfin testamos esse tipo de fluxo em casos pontuais, e nosso tutorial de n8n mostra como montar um. Para a maioria dos emails transacionais, Edge Function mais webhook do banco resolve com menos peças.
Templates de email transacional com React Email
Escrever HTML de email na mão é uma experiência que ninguém recomenda. Clientes de email ainda renderizam tabelas melhor do que flexbox, o Outlook ignora metade do CSS moderno e o modo escuro inverte cores de forma imprevisível. O React Email resolve boa parte disso com componentes que já saem compatíveis com os principais clientes.
Você escreve algo como <Html>, <Body>, <Container>, <Heading>, <Button> e <Text>, com estilos inline ou Tailwind, e a biblioteca converte para o HTML em tabelas que os clientes de email entendem. Tem um servidor de preview local para ver o template enquanto edita, e o SDK do Resend aceita o componente direto no campo react, sem precisar renderizar antes.
Numa Edge Function em Deno, dá para importar os pacotes via npm: e renderizar o componente para HTML antes de chamar a API. Num backend Next.js, o caminho é ainda mais direto: o template fica numa pasta emails/, você importa na route handler e passa para o resend.emails.send. Em projetos Next.js hospedados na Vercel, muitas vezes deixamos os emails de produto numa route handler do próprio app e usamos Edge Functions só para o que é disparado pelo banco.
Uma regra que seguimos: todo template tem versão em texto puro. O Resend gera uma automaticamente se você não mandar, mas revisar esse texto evita links quebrados e frases cortadas para quem lê email em clientes sem HTML. Também mantemos o email transacional curto, com um único botão de ação e o link completo em texto logo abaixo, para quem não consegue clicar no botão.
Como pedir essa integração para Claude Code e Cursor
Toda essa configuração cabe numa sessão com um agente de código. O Claude Code é a ferramenta que mais usamos na Marfin, e com o Opus 4.8, lançado em maio de 2026, ele consegue planejar a integração inteira, criar a Edge Function, os templates e as migrations, e rodar o deploy pelo terminal. Nosso tutorial de Claude Code mostra o fluxo completo de uso no dia a dia.
O que faz diferença é o briefing. Em vez de pedir "adicione envio de email", descrevemos o contexto: "O projeto usa Supabase com Auth já configurado. Crie uma Edge Function send-email que recebe userId e type, busca o email na tabela profiles, monta o conteúdo no servidor com templates React Email em português, envia pela API do Resend com Idempotency-Key e retorna erro 400 para tipo desconhecido. A chave fica no segredo RESEND_API_KEY. Não aceite endereço nem HTML vindos do cliente." Com esse nível de detalhe, o agente acerta a arquitetura e não abre brecha de segurança.
A parte de DNS e do painel do Supabase continua manual, ou via CLI e MCP quando o seu setup permite. O agente não tem acesso ao seu registrador de domínio, e é bom que não tenha. Peça para ele listar os registros que você precisa criar e confira no painel do Resend.
Para o building do dia a dia, usamos o Cursor, que integra com os modelos Claude e é onde ajustamos templates, revisamos o código gerado e iteramos no visual dos emails com o preview do React Email aberto ao lado. O tutorial de Cursor AI mostra esse fluxo em um projeto completo. Se você ainda está escolhendo o editor, nosso comparativo das melhores IDEs com IA cobre Cursor, Windsurf, Copilot e as outras opções do mercado.
Quem constrói em plataformas visuais também chega nesse ponto. No Lovable, o Agent Mode consegue criar a Edge Function no Supabase conectado ao projeto, e você só precisa adicionar o segredo com a API key. No Bolt.new e no V0 o caminho é parecido, com a diferença de que você geralmente copia o código para o backend. Em todos os casos, a configuração de domínio e o SMTP customizado do Auth seguem os mesmos passos deste guia.
Entregabilidade de email: webhooks, bounces e reputação
Enviar é metade do trabalho. A outra metade é saber o que aconteceu com cada email. O Resend tem webhooks que avisam o seu backend sobre eventos como email.delivered, email.bounced, email.complained, email.opened e email.clicked. Configuramos um webhook apontando para outra Edge Function que grava os eventos numa tabela email_events.
Com essa tabela, três coisas ficam possíveis. Você para de enviar para endereços que deram hard bounce, o que protege a sua reputação. Você identifica usuários que marcaram o email como spam e revisa o que foi enviado para eles. E o suporte consegue responder "seu email foi entregue às 14h32 no servidor do Gmail" em vez de "vamos investigar".
Os webhooks do Resend são assinados. Valide a assinatura antes de gravar qualquer coisa, senão qualquer pessoa pode mandar eventos falsos para o seu endpoint. O SDK oferece o método de verificação, e o Claude Code implementa isso bem quando você pede explicitamente.
Reputação de envio se constrói com o tempo. Um domínio novo que manda dez mil emails no primeiro dia levanta alertas nos provedores. Se o seu lançamento vai gerar um pico de cadastros, comece a enviar volumes menores algumas semanas antes, com emails de teste para a equipe e para usuários beta. Mantenha a taxa de bounce abaixo de 2% e a de reclamação de spam abaixo de 0,1%, que são os patamares que Gmail e Yahoo usam como referência.
Outro ponto que costuma passar batido: nunca misture email transacional e marketing no mesmo remetente. Se a sua newsletter gerar reclamações, os provedores penalizam o domínio inteiro, e os emails de reset de senha começam a cair no spam. Use subdomínios separados, como mail.seuapp.com.br para transacional e news.seuapp.com.br para campanhas.
Resend vs Amazon SES, Postmark, SendGrid e Brevo
O Resend não é a única opção, e em alguns cenários outra ferramenta faz mais sentido.
O Amazon SES é o mais barato em volume, cobrando cerca de US$ 0,10 por mil emails. Em troca, a configuração é mais trabalhosa: você precisa sair do sandbox da AWS pedindo aumento de limite, configurar IAM, montar sua própria observabilidade de bounces com SNS e escrever mais código. Para quem já vive dentro da AWS e manda centenas de milhares de emails por mês, compensa. Para um app recém-lançado, o tempo gasto não se paga.
O Postmark tem fama de ser o provedor com a melhor entregabilidade para email transacional, e separa formalmente os fluxos transacional e de broadcast em streams diferentes. A API é tão boa quanto a do Resend. O preço de entrada é um pouco mais alto e o plano gratuito é só para testes. Se o email é parte central do produto, como num app de agendamento em que o lembrete precisa chegar sem falha, vale considerar.
O SendGrid, da Twilio, é o veterano. Tem de tudo, de SMTP a editor visual de campanhas, mas a experiência de desenvolvedor ficou para trás e a entregabilidade no IP compartilhado dos planos baratos oscila. O Brevo, antigo Sendinblue, é forte em email marketing e tem uma parte transacional razoável, com a vantagem de juntar os dois num lugar só e suporte em português.
Para o perfil de projeto que mais construímos, com Supabase, Next.js e deploy na Vercel, o Resend tem a melhor relação entre tempo de configuração, preço e experiência de desenvolvimento. Trocamos para outra opção quando o volume ou uma exigência específica do cliente justifica.
Preços e planos
Os valores abaixo são os praticados pelo Resend na data desta publicação. Confira a página de preços antes de fechar o orçamento, porque os limites mudam com alguma frequência.
| Plano | Preço | Emails por mês | Destaques |
|---|---|---|---|
| Free | US$ 0 | 3.000 (limite de 100 por dia) | 1 domínio, API e SMTP, retenção curta de logs |
| Pro | US$ 20/mês | 50.000 | Vários domínios, sem limite diário, retenção maior |
| Scale | US$ 90/mês | 100.000 | Mais retenção, opção de IP dedicado |
| Enterprise | Sob consulta | Volume customizado | Suporte prioritário, SLA |
Do lado do Supabase, o SMTP customizado funciona em todos os planos, inclusive no Free. Edge Functions também entram no plano gratuito com uma cota de invocações que cobre com folga os emails de um app em validação. Quando o projeto cresce, o Pro de US$ 25 por mês amplia essas cotas. Somando os dois, um SaaS em fase inicial manda milhares de emails transacionais por mês com custo zero, e só começa a pagar quando já tem usuários suficientes para justificar.
Para referência de custo por email em volume alto, o Amazon SES segue como o mais barato, o Postmark cobra a partir de cerca de US$ 15 por mês para 10 mil emails e o SendGrid tem planos a partir de uns US$ 20 mensais.
8 dicas para email transacional que chega na caixa de entrada
1. Use um subdomínio só para transacional. Algo como mail.seuapp.com.br isola a reputação dos envios do produto. Se uma campanha ou um bug gerar reclamações, o email corporativo e os envios de marketing ficam protegidos, e vice-versa.
2. Configure SPF, DKIM e DMARC antes do lançamento. Sem esses três registros, Gmail e Yahoo tratam o seu email com desconfiança desde o primeiro envio. Comece o DMARC em p=none e endureça a política depois de algumas semanas lendo os relatórios.
3. Nunca exponha a API key no frontend. A chave do Resend vive em segredos da Edge Function ou em variáveis de ambiente do servidor. Se ela vazou no bundle, revogue na hora e gere outra.
4. Monte o email no servidor, não no cliente. A função recebe um identificador e um tipo de mensagem, busca os dados no banco e monta o conteúdo. Aceitar destinatário e HTML livres do navegador transforma o seu app num relay de spam.
5. Use chaves de idempotência. Retries de rede e cliques duplos geram emails duplicados, e usuário recebendo dois recibos abre ticket. O header Idempotency-Key com um identificador do evento resolve com uma linha.
6. Grave os eventos de entrega. Um webhook do Resend alimentando uma tabela no Supabase dá ao suporte a resposta exata sobre cada email e permite bloquear endereços com hard bounce automaticamente.
7. Traduza e personalize os templates do Auth. Os templates padrão do Supabase vêm em inglês e sem marca. Assunto em português, nome do produto no remetente e um botão claro aumentam a taxa de confirmação de cadastro de forma visível.
8. Teste em clientes reais. Mande cada template para contas no Gmail, Outlook e Apple Mail, no desktop e no celular, com modo escuro ligado. O preview do React Email ajuda, mas só o cliente real mostra como o Outlook vai quebrar o seu botão.
Email transacional é uma daquelas partes do produto que ninguém nota quando funciona e todo mundo nota quando falha. A boa notícia é que o setup completo, com domínio verificado, SMTP customizado no Supabase Auth, Edge Function para os emails de produto e webhook de eventos, cabe numa tarde de trabalho, e boa parte do código sai de uma sessão bem guiada com Claude Code. Depois disso, o seu app manda confirmação, reset de senha e boas-vindas com a sua marca, na caixa de entrada certa, e você passa a saber exatamente o que aconteceu com cada mensagem. Fazemos esse passo antes de abrir qualquer projeto para usuários reais, e recomendamos que você faça o mesmo.
Leia também:

