MailHog vs Mailpit: Testando E-mails de Verificação e Redefinição de Senha com Casdoor
MailHog e Mailpit são ambos servidores SMTP falsos para desenvolvimento: eles aceitam toda mensagem, mantêm-na e mostram-na em uma interface web em vez de entregá-la. Ambos usam as mesmas portas padrão, SMTP na 1025 e a interface web e API na 8025, então o endereço SMTP é smtp://127.0.0.1:1025 e a caixa de entrada está em http://127.0.0.1:8025 para qualquer um deles. A diferença é a manutenção: a última versão do MailHog, v1.0.1, foi lançada em agosto de 2020, enquanto o Mailpit lançou a v1.33.0 em 31 de outubro de 2026. Para um novo projeto, use o Mailpit. O Casdoor envia para ambos através de um provedor SMTP simples, permitindo testar códigos de cadastro, e-mails de redefinição de senha e links mágicos sem uma conta de e-mail real.
MailHog vs Mailpit em resumo
| MailHog | Mailpit | |
|---|---|---|
| Última versão | v1.0.1, 2020-08-11 | v1.33.0, 2026-10-31 |
| Último commit no branch padrão | 2022-08-02 | 2026-10-31 |
| Licença | MIT | MIT |
| Porta SMTP padrão | 1025 | 1025 |
| Porta padrão da interface web e API | 8025 | 8025 |
| Imagem Docker | mailhog/mailhog, somente amd64 | axllent/mailpit, amd64, arm64 e 386 |
| API HTTP | v1 e v2: listar, obter, excluir, pesquisar por from, to ou containing | v1: listar, obter, excluir, pesquisar com filtros como to: e subject:, atalho para mensagem latest |
| Armazenamento padrão | Em memória | Banco de dados SQLite temporário, excluído na saída |
| Armazenamento persistente | MongoDB ou Maildir | Arquivo SQLite (MP_DATABASE) ou rqlite |
| Limite de mensagens | Nenhum documentado | Mantém as 500 mais recentes por padrão (MP_MAX_MESSAGES) |
| Verificação HTML, verificação de links, verificação de spam | Não | Sim |
| Webhook em novo e-mail | Não | Sim (MP_WEBHOOK_URL) |
| SMTP TLS | Não oferecido | STARTTLS opcional ou SSL/TLS |
| Injeção de falhas | Jim | Chaos |
| Liberar uma mensagem para um servidor SMTP real | Sim | Sim |
| Servidor POP3 | Não | Sim, opcional |
| Autenticação básica para a interface web | Sim | Sim |
As contagens do Docker Hub mostram que muitas pessoas ainda baixam o MailHog. Isso reflete tutoriais antigos e arquivos de CI, não atividade: uma issue aberta no repositório do MailHog intitulada "THIS PROJECT IS DEAD!" tem uma resposta de 2023 do autor dizendo que ele não tem mais tempo para mantê-lo. O README do Mailpit se descreve como inspirado pelo MailHog e aponta para esse mesmo comentário.
A arquitetura da imagem importa mais do que parece. Em um laptop Apple Silicon ou em um runner ARM de CI, mailhog/mailhog roda apenas sob emulação, enquanto axllent/mailpit tem uma imagem nativa arm64.
Execute qualquer um deles com Docker
MailHog:
docker run -d --name mailhog -p 1025:1025 -p 8025:8025 mailhog/mailhog
Mailpit:
docker run -d --name mailpit -p 1025:1025 -p 8025:8025 axllent/mailpit
O Mailpit mantém os e-mails em um banco de dados temporário que desaparece quando o container é parado. Para mantê-lo entre reinicializações, monte um volume e defina MP_DATABASE:
docker run -d --name mailpit \
-v "$PWD/mailpit-data:/data" \
-e MP_DATABASE=/data/mailpit.db \
-p 1025:1025 -p 8025:8025 \
axllent/mailpit
Sem Docker, tanto brew install mailhog quanto brew install mailpit funcionam no macOS, e o Mailpit oferece binários estáticos para Windows, Linux e macOS em sua página de releases.
No GitHub Actions, execute-o como um container de serviço ao lado do seu job de teste:
services:
mailpit:
image: axllent/mailpit
ports:
- 1025:1025
- 8025:8025
Configure o Casdoor para usar o MailHog ou Mailpit
O Casdoor não tem um tipo de provedor separado para MailHog ou Mailpit, e não precisa de um. O tipo de e-mail Default envia via SMTP, e ambas as ferramentas são servidores SMTP.
- Como administrador global, adicione um provedor na organização
adminoubuilt-in. - Defina Category como
Emaile Type comoDefault. - Defina Host para onde a ferramenta é executada e Port para
1025. - Deixe Username e Password vazios.
- Clique em Test SMTP Connection, depois em Send Testing Email, e verifique a interface web na porta 8025.
As páginas passo a passo com capturas de tela são Test email with MailHog e Test email with Mailpit.
Alguns detalhes decidem se isso funciona na primeira tentativa:
Deixe o modo SSL em Auto ou defina-o para Disable. No modo Auto, o Casdoor usa TLS implícito apenas na porta 465 e faz upgrade com STARTTLS apenas se o servidor oferecer isso. Nem o MailHog nem um Mailpit padrão oferecem STARTTLS na porta 1025, então a conexão permanece sem criptografia. Não escolha Enable: isso força TLS implícito, e o handshake falha contra um servidor de texto plano. A tabela de modos SSL tem o comportamento completo.
Deixe as credenciais vazias. O Casdoor faz login no servidor SMTP apenas quando Username está definido. Se você preenchê-lo, a autenticação PLAIN do Go recusa enviar a senha sobre uma conexão não criptografada, a menos que o host seja localhost, então um MailHog em 192.168.x.x falha com um erro de autenticação, mesmo que o MailHog aceitaria qualquer login. O Mailpit, por padrão, não solicita autenticação.
Use o host correto. 127.0.0.1 funciona apenas quando o Casdoor e o coletor de e-mails rodam na mesma máquina. Se ambos rodarem no Docker Compose, use o nome do serviço, como mailpit, como host.
Use um provedor global. Um provedor pertencente a uma organização comum só pode acessar endereços da Internet, então não pode conectar-se a 127.0.0.1 ou a um IP privado. Provedores em admin ou built-in não têm restrições. Veja Which addresses a provider can reach.
Defina origin para os links. Os códigos de verificação funcionam imediatamente. Links de redefinição de senha e magic links precisam que o Casdoor saiba sua URL pública, através de origin em conf/app.conf ou de uma requisição em um host loopback. Caso contrário, o link de redefinição será omitido do e-mail e os magic links falharão. Veja Templates.
Finalmente, adicione o provedor à sua aplicação em Add providers to an application para que o cadastro e a redefinição de senha realmente o utilizem.
Leia o código de verificação em um teste automatizado
Os códigos de verificação do Casdoor têm seis dígitos, e o template padrão diz "Here is your code: " seguido pelo código. Um teste end-to-end cadastra um usuário, pede ao Casdoor para enviar o código, e depois lê-o pela API do coletor de e-mails.
Com o Mailpit, pesquise pelo destinatário e abra a correspondência mais recente. GET /api/v1/search retorna as correspondências da mais nova para a mais antiga, e GET /api/v1/message/{ID} retorna os corpos Text e HTML analisados:
import { request } from "@playwright/test";
const MAILPIT = process.env.MAILPIT_URL ?? "http://127.0.0.1:8025";
export async function latestCode(to: string): Promise<string> {
const api = await request.newContext({ baseURL: MAILPIT });
for (let i = 0; i < 20; i++) {
const res = await api.get("/api/v1/search", {
params: { query: `to:"${to}"`, limit: "1" },
});
const { messages } = await res.json();
if (messages.length > 0) {
const msg = await (await api.get(`/api/v1/message/${messages[0].ID}`)).json();
const match = (msg.Text || msg.HTML).match(/code: (\d{6})/);
if (match) return match[1];
}
await new Promise((r) => setTimeout(r, 500));
}
throw new Error(`no verification email for ${to}`);
}
Se apenas um teste enviar e-mails por vez, GET /api/v1/message/latest ignora a etapa de busca. Antes de cada teste, DELETE /api/v1/messages sem corpo limpa a caixa de entrada.
Com o MailHog, a chamada mais próxima é GET /api/v2/search?kind=to&query=<address>. As mensagens são retornadas da mais recente para a mais antiga em items, e o corpo está em items[0].Content.Body:
const res = await api.get("/api/v2/search", {
params: { kind: "to", query: to, limit: "1" },
});
const { items } = await res.json();
const body: string = items[0]?.Content.Body ?? "";
Content.Body é o corpo MIME bruto. O Casdoor envia em quoted-printable, então = se torna =3D e linhas longas recebem quebras suaves terminando em =. Decodifique-o primeiro ou mantenha o código no início de um modelo curto. Limpe o MailHog com DELETE /api/v1/messages.
Migrando do MailHog para o Mailpit
Como as portas correspondem, a maioria das migrações é uma alteração de uma linha no docker-compose.yml: substitua mailhog/mailhog por axllent/mailpit. O provedor do Casdoor mantém o mesmo host e porta. O que muda:
- Configurações. O MailHog lê variáveis
MH_*; o Mailpit lêMP_*. Se você usouMH_STORAGE=maildirou MongoDB, mude paraMP_DATABASE. - Auxiliares de teste. O Mailpit não possui endpoints
/api/v2. Reescreva chamadas para/api/v2/messagese/api/v2/searchpara/api/v1/messagese/api/v1/search, e leiamessages[].IDalém deTextouHTMLem vez deitems[].Content.Body. A decodificação quoted-printable desaparece. - Sintaxe de busca.
kind=to&query=a@example.comse tornaquery=to:"a@example.com". - Injeção de falhas. Jim não tem flags no Mailpit; use Chaos.
- Autenticação. Se um aplicativo insistir em fazer login via SMTP simples, inicie o Mailpit com
MP_SMTP_AUTH_ACCEPT_ANY=1eMP_SMTP_AUTH_ALLOW_INSECURE=1. Para o Casdoor, deixar as credenciais vazias é mais simples. - Retenção. O Mailpit exclui para manter apenas as 500 mensagens mais recentes por padrão. Aumente
MP_MAX_MESSAGESse uma execução de testes longa precisar de mais.
Indo para produção
MailHog e Mailpit nunca entregam e-mails a caixas de entrada reais, a menos que você libere as mensagens manualmente, portanto, a produção precisa de um provedor real. No Casdoor, você troca o provedor, não os modelos. Os modelos de e-mail, o placeholder de código %s e o bloco <reset-link> permanecem os mesmos:
- Qualquer servidor SMTP com o tipo
Default, descrito em Provedores de e-mail - SendGrid e Resend através de suas APIs
- Brevo através de seu relay SMTP
- Azure Communication Services
- Seu próprio endpoint HTTP com Custom HTTP Email
Uma configuração comum mantém o Mailpit no desenvolvimento e CI e o provedor real na produção. Cada ambiente aponta sua aplicação para um provedor diferente, para que o fluxo de cadastro que você testa seja o que será enviado.
Referências
- Repositório MailHog e README: https://github.com/mailhog/MailHog
- Documentação de configuração e API v1/v2 do MailHog: https://github.com/mailhog/MailHog/tree/master/docs
- Comentário sobre manutenção do MailHog: https://github.com/mailhog/MailHog/issues/442#issuecomment-1493415258
- Repositório Mailpit e README: https://github.com/axllent/mailpit
- Documentação do Mailpit (Docker, armazenamento, SMTP, webhook, filtros de busca): https://mailpit.axllent.org/docs/
- Referência da API v1 do Mailpit: https://mailpit.axllent.org/docs/api-v1/
- Código do provedor de e-mail do Casdoor: https://github.com/casdoor/casdoor/tree/master/email