Enviando E-mails Transacionais no SaaS Boilerplate
O SaaS Boilerplate inclui um sistema de e-mails transacionais completo e flexível, projetado para ser facilmente personalizável e independente de provedores específicos.
Visão Geral
O sistema de e-mails transacionais do SaaS Boilerplate foi desenvolvido com os seguintes princípios:
- Arquitetura de adaptadores: Troque facilmente entre diferentes provedores de e-mail
- Templates React: Crie e-mails bonitos e responsivos usando componentes React
- Tipagem forte: Evite erros em tempo de execução com validação de dados via Zod
- Facilidade de teste: Teste seus e-mails localmente sem enviar mensagens reais
Configuração Inicial
1. Configuração do Provedor
O sistema usa uma arquitetura de adaptadores que permite trocar facilmente entre diferentes provedores de e-mail:
// Em src/core/providers/mail.ts
import { MailProvider } from "@/saas-boilerplate/providers/mail/mail.provider";
import { AppConfig } from "@/configs/app.config";
import { getAdapter } from "@/saas-boilerplate/providers/mail";
import { welcomeEmailTemplate } from "@/content/mails/welcome.email";
import { organizationInviteTemplate } from "@/content/mails/organization-invite";
import { planUpgradeEmailTemplate } from "@/content/mails/billing-plan-upgrade";
import { quotaExceededEmailTemplate } from "@/content/mails/billing-plan-quota-exceed";
import { downgradeEmailTemplate } from "@/content/mails/billing-plan-downgrade";
import { otpCodeEmailTemplate } from "@/content/mails/otp-code";
export const mail = MailProvider.initialize({
secret: AppConfig.providers.mail.secret,
from: AppConfig.providers.mail.from,
adapter: getAdapter(AppConfig.providers.mail.provider),
templates: {
welcome: welcomeEmailTemplate,
'organization-invite': organizationInviteTemplate,
'billing-plan-upgrade': planUpgradeEmailTemplate,
'billing-plan-quota-exceed': quotaExceededEmailTemplate,
'billing-plan-downgrade': downgradeEmailTemplate,
'otp-code': otpCodeEmailTemplate,
}
})
2. Configuração de Variáveis de Ambiente
Configure as variáveis de ambiente para o provedor de e-mail que você deseja usar:
# .env # Para SMTP MAIL_PROVIDER=smtp MAIL_SECRET=smtp://username:[email protected]:587 # OU para Resend MAIL_PROVIDER=resend MAIL_SECRET=re_123456789
Templates de E-mail
Criando um Template
Os templates de e-mail são criados usando React Email, permitindo que você use componentes React para criar e-mails bonitos e responsivos:
// Em src/content/mails/welcome.email.tsx
import * as ReactEmail from '@react-email/components'
import { z } from 'zod'
import { Footer } from './components/footer'
import { Url } from '@/saas-boilerplate/utils'
import { AppConfig } from '@/configs/app.config'
import { MailProvider } from '@/saas-boilerplate/providers/mail'
/**
* Schema definition for the welcome email template
*/
const schema = z.object({
name: z.string().nullable().optional(),
email: z.string().email()
})
/**
* Email template for welcoming new users to the platform
*/
export const welcomeEmailTemplate = MailProvider.template({
subject: `Bem-vindo ao ${AppConfig.name}!`,
schema: schema,
render: ({ name, email }) => {
return (
<ReactEmail.Html>
<ReactEmail.Head />
<ReactEmail.Preview>Bem-vindo ao {AppConfig.name}</ReactEmail.Preview>
<ReactEmail.Tailwind>
<ReactEmail.Body className="mx-auto my-auto bg-white font-sans">
<ReactEmail.Container className="mx-auto my-10 max-w-[500px] rounded-md border border-solid border-gray-200 px-10 py-5">
<ReactEmail.Section className="mt-8">
<ReactEmail.Img
src={AppConfig.brand.logos.icon.light}
width="40"
height="40"
alt={AppConfig.name}
className="my-0"
/>
</ReactEmail.Section>
<ReactEmail.Heading className="mx-0 my-7 p-0 text-left text-xl font-semibold text-black">
Bem-vindo ao {AppConfig.name}
</ReactEmail.Heading>
<ReactEmail.Text className="text-sm leading-6 text-black">
Obrigado por se cadastrar{name && `, ${name}`}!
</ReactEmail.Text>
{/* Mais conteúdo do e-mail... */}
<Footer email={email} marketing />
</ReactEmail.Container>
</ReactEmail.Body>
</ReactEmail.Tailwind>
</ReactEmail.Html>
)
}
})
Cada template inclui:
- Schema de validação: Define os dados necessários para renderizar o template
- Assunto do e-mail: Pode incluir variáveis dinâmicas
- Função de renderização: Retorna o JSX que será convertido em HTML
Templates Incluídos
O SaaS Boilerplate inclui templates prontos para uso em todos os momentos críticos da jornada do usuário:
- Boas-vindas: Enviado quando um usuário se cadastra
- Convite para Organização: Para convidar novos membros para uma equipe
- Código OTP: Para autenticação de dois fatores
- Upgrade de Plano: Notifica sobre mudanças de plano
- Limite Excedido: Avisa quando um limite de uso foi atingido
- Downgrade de Plano: Informa sobre rebaixamento de plano
Enviando E-mails
Envio Básico
Para enviar um e-mail usando um template:
import { mail } from "@/core/providers/mail";
// Enviar um e-mail de boas-vindas
await mail.send({
template: 'welcome',
to: '[email protected]',
data: {
name: 'João Silva',
email: '[email protected]'
}
});
Agendamento de E-mails
Você também pode agendar e-mails para serem enviados no futuro:
import { mail } from "@/core/providers/mail";
// Data para 3 dias no futuro
const dataFutura = new Date();
dataFutura.setDate(dataFutura.getDate() + 3);
// Agendar um e-mail para ser enviado em 3 dias
await mail.schedule({
template: 'dica-semanal',
to: '[email protected]',
data: {
name: 'João Silva',
email: '[email protected]',
dicas: [
{ titulo: 'Como criar seu primeiro projeto', link: '/docs/primeiros-passos' },
{ titulo: 'Integrando com APIs externas', link: '/docs/integrações' }
]
}
}, dataFutura);
Provedores de E-mail
Adaptadores Incluídos
O sistema inclui adaptadores para os seguintes provedores:
SMTP
// Em src/saas-boilerplate/providers/mail/adapters/smtp.adapter.ts
import nodemailer from 'nodemailer';
import { IMailAdapter, MailAdapterSendParams } from '../interfaces/adapter.interface';
export const smtpAdapter: IMailAdapter = {
send: async (options: MailAdapterSendParams) => {
const { to, subject, html, text, from, scheduledAt } = options;
const transporter = nodemailer.createTransport(options.secret);
const mailOptions = {
from: from,
to,
subject,
html,
text,
date: scheduledAt
};
await transporter.sendMail(mailOptions);
}
};
Resend
// Em src/saas-boilerplate/providers/mail/adapters/resend.adapter.ts
import { Resend } from 'resend';
import { IMailAdapter, MailAdapterSendParams } from '../interfaces/adapter.interface';
export const resendAdapter: IMailAdapter = {
send: async (options: MailAdapterSendParams) => {
const { to, subject, html, text, from, secret, scheduledAt } = options;
const resend = new Resend(secret);
await resend.emails.create({
to,
from,
subject,
html,
text,
scheduledAt: scheduledAt?.toISOString()
});
}
};
Criando um Novo Adaptador
Para adicionar suporte a um novo provedor de e-mail, crie um novo adaptador:
// Em src/saas-boilerplate/providers/mail/adapters/meu-provedor.adapter.ts
import { IMailAdapter, MailAdapterSendParams } from '../interfaces/adapter.interface';
export const meuProvedorAdapter: IMailAdapter = {
send: async (options: MailAdapterSendParams) => {
const { to, subject, html, text, from, secret, scheduledAt } = options;
// Implementação específica do provedor
// ...
}
};
Personalização
Branding
Para personalizar o branding dos e-mails, edite as configurações em src/configs/app.config.ts:
export const AppConfig = {
name: 'Meu SaaS',
brand: {
logos: {
icon: {
dark: '/assets/logo-icon-light.svg',
light: '/assets/logo-icon-dark.svg',
},
full: {
dark: '/assets/logo-dark-light.svg',
light: '/assets/logo-dark-dark.svg',
},
},
},
creator: {
name: 'Seu Nome',
// ...
},
// ...
}
Componentes Reutilizáveis
Crie componentes reutilizáveis para manter a consistência entre seus templates:
// Em src/content/mails/components/button.tsx
import * as ReactEmail from '@react-email/components'
export const Button = ({
href,
children
}: {
href: string;
children: React.ReactNode
}) => {
return (
<ReactEmail.Button
href={href}
className="rounded bg-blue-600 px-4 py-2 font-semibold text-white"
>
{children}
</ReactEmail.Button>
);
};
Testes
Teste Local com MailHog
Para testar seus e-mails localmente sem enviá-los para destinatários reais, use o MailHog:
- Instale o MailHog usando Docker:
docker run -d -p 1025:1025 -p 8025:8025 mailhog/mailhog
- Configure o adaptador SMTP para usar o MailHog:
MAIL_PROVIDER=smtp MAIL_SECRET=smtp://localhost:1025
- Acesse a interface do MailHog em
http://localhost:8025para ver os e-mails enviados.
Pré-visualização de Templates
Para visualizar seus templates sem enviar e-mails:
// Em src/app/mail-preview/page.tsx
import { welcomeEmailTemplate } from '@/content/mails/welcome.email';
export default function MailPreviewPage() {
return (
<div>
{welcomeEmailTemplate.render({
name: 'Usuário de Teste',
email: '[email protected]'
})}
</div>
);
}
Considerações de Segurança
- Nunca inclua informações sensíveis em e-mails transacionais
- Valide os endereços de e-mail antes de enviar mensagens
- Use SPF, DKIM e DMARC para melhorar a entregabilidade e segurança
- Implemente rate limiting para evitar abuso do sistema de e-mail
Melhores Práticas
- Mantenha os e-mails simples e diretos: Foque em uma única ação por e-mail
- Otimize para dispositivos móveis: A maioria dos e-mails é lida em smartphones
- Teste em diferentes clientes de e-mail: Outlook, Gmail, Apple Mail, etc.
- Personalize o conteúdo: Use o nome do usuário e outras informações relevantes
- Inclua texto alternativo: Para clientes de e-mail que não suportam HTML
Próximos Passos
- Personalize os templates existentes para corresponder à sua marca
- Crie novos templates para pontos específicos da jornada do usuário
- Configure o provedor de e-mail de sua preferência
- Implemente testes A/B para otimizar suas taxas de abertura e clique
Com este sistema implementado, você pode oferecer uma experiência de comunicação profissional e consistente para seus usuários em todos os pontos de contato.
Quer desenvolver um SaaS em um final de semana?
Um único comando no terminal e pronto, você já tem seu projeto criado, com site, blog, central de ajuda, autenticação, onboarding, dashboard, emails... Para resumir, é assim que eu crio os meus SaaS em um Final de Semana.
Conheça minha estratégia