Перейти до основного вмісту

MailHog vs Mailpit: тестування листів верифікації та скидання пароля з Casdoor

· Читання за 9 хв
Yang Luo
Casdoor Maintainer

MailHog і Mailpit — це фальшиві SMTP-сервери для розробки: вони приймають усі повідомлення, зберігають їх і показують у веб-інтерфейсі замість доставки. Обидва використовують ті самі порти за замовчуванням, SMTP на 1025 та веб-інтерфейс і API на 8025, тому адреса SMTP — smtp://127.0.0.1:1025, а скринька знаходиться за адресою http://127.0.0.1:8025 для обох. Відмінність полягає в підтримці: останній реліз MailHog, v1.0.1, вийшов у серпні 2020 року, тоді як Mailpit випустив v1.33.0 31 жовтня 2026 року. Для нового проекту використовуйте Mailpit. Casdoor надсилає листи через звичайного SMTP-провайдера до обох, тому ви можете тестувати коди реєстрації, листи для скидання пароля та магічні посилання без реального поштового акаунта.

MailHog vs Mailpit коротко​

MailHogMailpit
Останній релізv1.0.1, 2020-08-11v1.33.0, 2026-10-31
Останній коміт у гілці за замовчуванням2022-08-022026-10-31
ЛіцензіяMITMIT
Стандартний порт SMTP10251025
Стандартний порт веб-інтерфейсу та API80258025
Образ Dockermailhog/mailhog, лише amd64axllent/mailpit, amd64, arm64 і 386
HTTP APIv1 і v2: список, отримання, видалення, пошук за from, to або containingv1: список, отримання, видалення, пошук із фільтрами, такими як to: і subject:, ярлик для останнього повідомлення (latest)
Стандартне сховищеУ пам'ятіТимчасова база даних SQLite, видаляється при виході
Стійке зберіганняMongoDB або MaildirФайл SQLite (MP_DATABASE) або rqlite
Обмеження кількості повідомленьНе задокументованоЗа замовчуванням зберігає 500 найновіших (MP_MAX_MESSAGES)
Перевірка HTML, посилань, спамуНіТак
Webhook для нової поштиНіТак (MP_WEBHOOK_URL)
TLS для SMTPНе пропонуєтьсяОпціональний STARTTLS або SSL/TLS
Імітація збоївJimChaos
Надсилання повідомлення на реальний сервер SMTPТакТак
Сервер POP3НіТак, опціонально
Базова автентифікація для веб-інтерфейсуТакТак

Лічильники завантажень на Docker Hub показують, що багато людей досі використовують MailHog. Це відображає старі підручники та файли CI, а не активність: у відкритому питанні (issue) у репозиторії MailHog із назвою "THIS PROJECT IS DEAD!" є відповідь автора з 2023 року, де він каже, що більше не має часу на підтримку проєкту. README Mailpit описує його як натхненний MailHog і посилається на той самий коментар.

Архітектура образу важливіша, ніж здається. На ноутбуках Apple Silicon або ARM-раннерах CI mailhog/mailhog працює лише в режимі емуляції, тоді як axllent/mailpit має нативний образ arm64.

Запуск будь-якого з них через 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

Mailpit зберігає листи в тимчасовій базі даних, яка зникає після зупинки контейнера. Щоб зберегти їх між перезапусками, монтируйте том і встановіть 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

Без Docker, brew install mailhog і brew install mailpit обидва працюють на macOS, а Mailpit також надає статичні бінарні файли для Windows, Linux і macOS на своїй сторінці випусків.

У GitHub Actions запустіть його як сервісний контейнер поруч із вашим тестовим завданням:

services:
mailpit:
image: axllent/mailpit
ports:
- 1025:1025
- 8025:8025

Налаштування Casdoor для роботи з MailHog або Mailpit​

Casdoor не має окремого типу провайдера для MailHog або Mailpit, і йому це не потрібно. Тип email Default надсилає листи через SMTP, а обидва інструменти є серверами SMTP.

  1. Як глобальний адміністратор, додайте провайдер в організацію admin або built-in.
  2. Встановіть Category як Email, а Type — як Default.
  3. Встановіть Host на адресу, де працює інструмент, і Port на 1025.
  4. Залиште поля Username і Password порожніми.
  5. Натисніть Test SMTP Connection, потім Send Testing Email і перевірте веб-інтерфейс на порту 8025.

Покрокові інструкції зі скріншотами доступні тут: Тестування email з MailHog та Тестування email з Mailpit.

Кілька деталей визначають, чи спрацює це з першої спроби:

Залиште режим SSL на Auto або встановіть Disable. У режимі Auto Casdoor використовує неявний TLS лише на порту 465 і переходить на STARTTLS, лише якщо сервер це пропонує. Ні MailHog, ні стандартний Mailpit не пропонують STARTTLS на порту 1025, тому з'єднання залишається незашифрованим. Не обирайте Enable: це примусово вмикає неявний TLS, і рукостискання (handshake) завершиться помилкою проти текстового сервера. Повну поведінку описано в таблиці режимів SSL.

Залиште облікові дані порожніми. Casdoor виконує вхід до сервера SMTP лише якщо вказано Username. Якщо ви заповните це поле, автентифікація PLAIN у Go відмовиться надсилати пароль через незашифроване з'єднання, якщо хост не localhost. Тому MailHog на адресі 192.168.x.x видасть помилку автентифікації, хоча MailHog прийняв би будь-який логін. Mailpit за замовчуванням взагалі не вимагає автентифікації.

Використовуйте правильний хост. 127.0.0.1 працює лише коли Casdoor і перехоплювач пошти працюють на одній машині. Якщо обидва запускаються в Docker Compose, використовуйте ім'я сервісу, наприклад mailpit, як хост.

Використовуйте глобальний провайдер. Провайдер, що належить звичайній організації, може звертатися лише до інтернет-адрес, тому він не зможе підключитися до 127.0.0.1 або приватної IP-адреси. Провайдери в admin або built-in не мають таких обмежень. Дивіться Які адреси можуть бути досяжні провайдером.

Встановіть origin для посилань. Коди верифікації працюють одразу. Посилання для скидання пароля та магічні посилання потребують того, щоб Casdoor знав свою публічну URL-адресу, через параметр origin у conf/app.conf або запит з локального хоста (loopback). В іншому випадку посилання для скидання буде пропущено в листі, а магічні посилання не працюватимуть. Дивіться Шаблони.

Нарешті, додайте провайдер до вашого додатка в розділі Додавання провайдерів до додатка, щоб реєстрація та скидання пароля дійсно використовували його.

Читання коду верифікації в автоматизованому тесті​

Коди верифікації Casdoor складаються з шести цифр, і стандартний шаблон містить текст "Here is your code: ", за яким йде код. Енд-to-end тест реєструє користувача, просить Casdoor надіслати код, а потім зчитує його з API перехоплювача пошти.

У Mailpit шукайте за отримувачем і відкрийте найновіший результат. GET /api/v1/search повертає результати від найновіших до найстаріших, а GET /api/v1/message/{ID} повертає розібрані тіла Text і HTML:

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}`);
}

Якщо лише один тест надсилає лист за раз, GET /api/v1/message/latest пропускає крок пошуку. Перед кожним тестом виклик DELETE /api/v1/messages без тіла запиту очищує вхідні повідомлення.

У MailHog найближчий аналог — це GET /api/v2/search?kind=to&query=<address>. Повідомлення повертаються у полі items від найновіших до найстаріших, а текст листа міститься в 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 містить сирий MIME-тіло. Casdoor використовує кодування quoted-printable, тому символ = перетворюється на =3D, а довгі рядки мають м’які переноси, що закінчуються на =. Спочатку декодуйте його або розміщуйте код на початку короткого шаблону. Очистіть MailHog командою DELETE /api/v1/messages.

Міграція з MailHog на Mailpit​

Оскільки порти збігаються, більшість міграцій полягають у однорядковій зміні в docker-compose.yml: замініть mailhog/mailhog на axllent/mailpit. Провайдер Casdoor залишає той самий хост і порт. Що змінюється:

  • Налаштування. MailHog читає змінні MH_*; Mailpit читає MP_*. Якщо ви використовували MH_STORAGE=maildir або MongoDB, перейдіть на MP_DATABASE.
  • Тестові допоміжні функції. Mailpit не має ендпоінтів /api/v2. Перепишіть виклики до /api/v2/messages та /api/v2/search на /api/v1/messages та /api/v1/search, і читайтесь messages[].ID плюс Text або HTML замість items[].Content.Body. Декодування quoted-printable більше не потрібне.
  • Синтаксис пошуку. kind=to&query=a@example.com змінюється на query=to:"a@example.com".
  • Імітація збоїв. У Jim немає прапорців для Mailpit; використовуйте Chaos.
  • Автентифікація. Якщо додаток наполягає на вході через незахищений SMTP, запустіть Mailpit зі змінними MP_SMTP_AUTH_ACCEPT_ANY=1 та MP_SMTP_AUTH_ALLOW_INSECURE=1. Для Casdoor простіше залишити облікові дані порожніми.
  • Зберігання даних. За замовчуванням Mailpit видаляє старі повідомлення, залишаючи лише 500 найновіших. Збільште MP_MAX_MESSAGES, якщо тривалий тестовий прогон потребує більше місця.

Перехід до продуктивного середовища​

MailHog і Mailpit ніколи не доставляють листи на реальні поштові скриньки, якщо ви вручну не випускаєте повідомлення, тому для продуктивного середовища потрібен реальний провайдер. У Casdoor ви замінюєте провайдера, а не шаблони. Шаблони електронної пошти, заповнювач %s для коду та блок <reset-link> залишаються незмінними:

Поширена конфігурація: Mailpit залишається в середовищі розробки та CI, а реальний провайдер — у продуктивному середовищі. Кожне середовище вказує свій додаток на різного провайдера, тому потік реєстрації, який ви тестуєте, є тим самим, що й у продакшені.

Посилання​