Executando verificação de segurança...
8

📧 Contatando o Usuário: Testando o Envio de E-Mails

Uma aplicação, diversas vezes, precisa entrar em contato com o usuário, mas eu não estou falando da interface do usuário, o assunto desse post é o envio de e-mails.

Olha,

  • Se cadastrou? E-mail de ativação de conta.
  • Precisar recuperar a senha? E-mail de novo.
  • Fez alterações na conta? Um e-mail de aviso.
  • Alertas e notificações? Vai de e-mail também.

Que a realidade é essa é indiscutível.

Para quem tá iniciando, é muito comum implementar isso já para "produção" e verificar se tá funcionando enviando mensagens para as contas de e-mail que possui.

Porém, convenhamos, ficar enviando e-mails para as suas próprias contas como teste é péssimo. No mínimo você fica preso a um único endereço para testar.

Um bom ambiente de testes precisa permitir que mais cenários possam ser validados. E é aqui que o MailHog entra, pois ele é um servidor SMTP (Simple Mail Transfer Protocol) "falso".

E o que é um Servidor SMTP?

Basicamente, é pra onde você envia os seus e-mails para que eles sejam enviados ao destinatário (é meio o que o Correios faz).

Fluxo de Envio de E-Mail Simplificado

Figura 1: Fluxo de Envio de E-Mail Simplificado

Mas como o MailHog é um servidor de SMTP falso, ele vai fazer algo um pouquinho diferente. Nele, TODOS os e-mails que são recebidos (ou seja, que você envia para ele, pela porta 1025), ao invés de serem redirecionados ao e-mail do destinatário, são centralizados e acessíveis ao desenvolvedor por meio de uma interface web (acessível pela porta 8025).

Fluxo de Envio de E-Mail com MailHog

Figura 2: Fluxo de Envio de E-Mail com MailHog

Foi isso que implementei no MinhaDespesa mais recentemente, meu projetinho pessoal onde me aprofundo no desenvolvimento web usando PHP. "Só" precisei baixar a imagem do MailHog e subir o container com docker compose up.

  mailhog:
      image: mailhog/mailhog:latest
      container_name: mailhog
      restart: always
      ports:
        - 1025:1025
        - 8025:8025

Levando o e-mail até o servidor...

Bem, quando disse "só" eu exagerei, não foi só isso, agora vem a parte mais interessante. O servidor (MailHog) estava de pé, mas ainda faltava configurar a máquina para enviar o e-mail para àquele servidor em específico.

Eu estou usando a imagem php:8.2-apache e a ferramenta (ou agente) padrão no PHP é o sendmail, que não vem instalado, mas é o que ele procura quando uso o mail().

O sendmail é um MTA (Mail Transfer Agent) robusto e muito completo (pode atuar como servidor SMTP, recebe e-mails, gerencia filas, faz roteamento e etc.). Para simplesmente enviar e-mails até o MailHog ele é até robusto demais. Explorando mais sobre isso descobri outra solução: msmtp.

O msmtp é um Cliente SMTP e ele faz – quase que exclusivamente – a funcionalidade que precisava: encaminha o e-mail para um servidor SMTP. Agora, só instalar no container através do Dockerfile:

# Baixa o `msmtp`
RUN apt-get install -y msmtp 

# Copia o arquivo de configuração para o container
COPY msmtprc /etc/msmtprc

# Muda o dono (CHange OWNer) do arquivo e passa a ser do usuário e grupo www-data
RUN chown www-data:www-data /etc/msmtprc

# Dentro de `msmtp.ini` muda o executável para o msmtp
RUN echo "sendmail_path = /usr/bin/msmtp -t -i" > /usr/local/etc/php/conf.d/msmtp.ini

O arquivo msmtprc ficou assim

defaults
auth           off
tls            off
logfile        /var/log/msmtp.log

account        default
host           mailhog
port           1025
from           [email protected]

Agora e-mails à vontade

Finalmente, quando chamo a função mail() no PHP, ao invés do utilitário procurado ser o sendmail (que não estava instalado) agora é o msmtp.

$to = $user->email;
$subject = 'Confirmação de cadastro';
$message = 'Clique no link para confirmar seu registro: http://localhost:8080/register/confirm?token=' . $user->token;
$headers = 'From: [email protected]' . "\r\n" . 'Reply-To: [email protected]' . "\r\n" . 'X-Mailer: PHP/' . phpversion();

$sent = mail($to, $subject, $message, $headers); # true se o e-mail foi enviado e falso caso contrário

Isso me permite testar o cadastro do usuário com ativação de conta por e-mail utilizando diversos e-mails que não são meus (sem incomodar nenhum dos meus amigos).

O que fica de aprendizado maior, pra mim, é que mesmo que eu não precisasse ter feito isso, afinal é um projeto pessoal, não me contive, me expus à essa experiência e agora tenho certeza que estou mais apto para lidar com problemas semelhantes, o que é recompensador. É assim que se torna experiente, fazendo o dever de casa. Então se exponha, é importante para evoluir.


Algum comentário a respeito? Não sou nem de longe o maior conhecedor de como e-mails funcionam, mas sinto que entendi a superficie desse assunto. Agora é continuar estudando.

Carregando publicação patrocinada...
3

Post muito interessante. Estou implementando disparo de e-mails em um projeto pessoal, porém, estou usando o próprio nodemailer com a minha conta pessoal ;-; agora com o seu post tenho uma solução melhor para o ambiente local e de dev. Valeu pelo post mano

2
1

se vc estiver usando node / express puro, vale a pena dar uma olhada no resend junto com o react email. se estiver usando um nestjs vale a pena dar uma olhada em algumas soluções de cloud como AWS SES ou o AWS Pinpoint, os dois tem free tier bem grandes, tem as soluções da azure tbm porem elas n tem free tier mas são mais baratas se for pagar