Troquei o Resend pelo Brevo e foi a melhor decisão do projeto
Comecei o sistema com Resend porque era o que todo tutorial mandava usar. Só que quando o volume transacional subiu, o custo e o limite não fecharam mais. Dito isso, aqui está exatamente o que eu ganhei e o que eu perdi na troca.
O que eu usava
O sistema mandava três tipos de e-mail: confirmação de cadastro, aviso de vencimento de prazo e o resumo semanal. Nada sofisticado. O Resend entrou porque era o que aparecia em todo tutorial de Next.js, a documentação é boa e a integração leva quinze minutos.
Funcionou por uns quatro meses sem eu pensar no assunto - e é isso que eu esperava de uma ferramenta de e-mail. Ferramenta boa é a que eu esqueço que existe.
O que doeu
O aviso de pendência é disparado por cliente, não por usuário. Quando o segundo cliente entrou no portal, o volume triplicou de uma semana para a outra. Aí apareceram duas coisas ao mesmo tempo:
- o limite do plano começou a bater no meio do dia, e o disparo da tarde entrava na fila;
- o custo por mil envios, na faixa em que eu estava caindo, ficou difícil de defender.
Acredito eu que o erro não foi escolher o Resend. Foi escolher sem estimar volume - eu simplesmente não tinha pensado em quantos e-mails o sistema mandaria com dez clientes dentro.
O que eu deveria ter feito antes: uma conta de guardanapo. Clientes × equipamentos × avisos por mês. Levava cinco minutos e teria mudado a escolha.
Pra onde eu fui
Fui para o Brevo. O que decidiu não foi preço: foi o plano ter fila própria, então disparo em lote deixou de ser problema meu. Ou seja, eu troquei um problema de código por um problema de configuração - e problema de configuração eu resolvo uma vez.
A troca em si foi pequena, porque o envio já estava atrás de uma função só. Isto é o arquivo inteiro depois da migração:
// Uma função só. Trocar de provedor mexe aqui e em lugar nenhum mais.
import { BrevoClient } from '@getbrevo/brevo'
const cliente = new BrevoClient(process.env.BREVO_API_KEY!)
export async function enviar(para: string, assunto: string, html: string) {
const r = await cliente.transactionalEmails.send({
to: [{ email: para }],
sender: { email: 'nao-responda@meudominio.com.br', name: 'Portal' },
subject: assunto,
htmlContent: html,
})
// Log do id: sem isso, "o cliente diz que não recebeu" é indefensável.
console.info('[email] enviado', { para, messageId: r.messageId })
return r.messageId
}Repare no console.info com o messageId. Isso não estava no código antigo, e foi o que mais me ajudou depois: quando um cliente diz que não recebeu, eu tenho o número do envio para procurar no painel do provedor. Sem isso, a conversa vira "mandei sim" contra "não chegou".
O que eu ganhei
- Fila no provedor. Disparo em lote parou de ser problema de código.
- Custo previsível na faixa de volume em que eu de fato estou.
- Rastreabilidade: agora eu sei o número de cada envio.
O que eu perdi
E essa é a parte que quase ninguém escreve, então vai completa:
- A documentação do Brevo é pior. Levei uma tarde para achar a forma certa de mandar o remetente.
- O painel é mais pesado e tem muita coisa de marketing que eu não uso.
- Perdi um dia de trabalho na troca. Um dia que não virou funcionalidade nenhuma para o cliente.
Troca de ferramenta nunca é de graça. Quando alguém te conta só o lado bom, ou a troca foi recente demais, ou tem link de indicação no meio.
Se eu começasse hoje
Faria a conta de guardanapo antes, e manteria o envio atrás de uma função só desde o primeiro dia - foi isso que fez a migração ser um arquivo em vez de uma refatoração.
Fica uma dúvida honesta minha: em que ponto vale sair de um serviço gerenciado e mandar e-mail por conta própria? Eu não sei responder - e desconfio que a resposta é "quase nunca", só que não tenho número para defender isso.
Escrito por Vinícius · desenvolvedor de sistemas · ver perfil →