メインコンテンツにスキップ

MailHog vs Mailpit: Casdoorでの確認メールおよびパスワード再設定メールのテスト

· 1分読む
Yang Luo
Casdoor Maintainer

MailHogとMailpitはどちらも開発用の偽SMTPサーバーです: すべてのメッセージを受信・保存し、実際の配信ではなくWeb UIに表示します。両者とも同じデフォルトポートを使用するため、SMTPは1025、Web UIとAPIは8025です。したがって、どちらの場合もSMTPアドレスはsmtp://127.0.0.1:1025、受信箱はhttp://127.0.0.1:8025になります。違いはメンテナンス状況です。MailHogの最後のリリースv1.0.1は2020年8月のものであり、Mailpitは2026年10月31日にv1.33.0をリリースしました。新規プロジェクトではMailpitを使用してください。Casdoorは通常のSMTPプロバイダーを通じて両方に送信するため、実際のメールアカウントなしでサインアップコード、パスワード再設定メール、マジックリンクをテストできます。

MailHog vs Mailpit 早見表​

MailHogMailpit
最新リリースv1.0.1, 2020-08-11v1.33.0, 2026-10-31
デフォルトブランチでの最終コミット2022-08-022026-10-31
ライセンスMITMIT
デフォルト SMTP ポート10251025
デフォルト Web UI および API ポート80258025
Docker イメージmailhog/mailhog, amd64 のみaxllent/mailpit, amd64、arm64 および 386
HTTP APIv1 および v2: list, get, delete, from, to または containing による検索v1: list, get, delete, to: や subject: などのフィルターによる検索、latest メッセージショートカット
デフォルトストレージインメモリ一時 SQLite データベース、終了時に削除
永続的ストレージMongoDB または MaildirSQLite ファイル (MP_DATABASE) または rqlite
メッセージ制限記載なしデフォルトで最新の 500 件を保持 (MP_MAX_MESSAGES)
HTML チェック、リンクチェック、スパムチェックいいえはい
新着メールの Webhookいいえはい (MP_WEBHOOK_URL)
SMTP TLS提供されませんオプションの STARTTLS または SSL/TLS
障害注入JimChaos
リアルな SMTP サーバーへのメッセージリリースはいはい
POP3 サーバーいいえはい、オプション
Web UI の Basic 認証はいはい

Docker Hub のカウントによると、多くの人がまだ MailHog をプルしています。これは古いチュートリアルや CI ファイルを反映しており、アクティブさを示すものではありません。MailHog リポジトリにある「THIS PROJECT IS DEAD!」というタイトルのオープンな Issue には、作者がもう維持する時間がないと述べる 2023 年の返信があります。Mailpit の README は、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 なしでは、macOS 上で brew install mailhog と brew install mailpit の両方が機能し、Mailpit はリリースページで Windows、Linux、macOS 用の静的バイナリを提供しています。

GitHub Actions では、テストジョブの横にあるサービスコンテナとして実行します:

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

Casdoor を MailHog または Mailpit に向ける​

Casdoor には MailHog や Mailpit 用の個別のプロバイダータイプがなく、必要ありません。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 の Web UI を確認します。

スクリーンショット付きのステップバイステップページは Test email with MailHog および Test email with Mailpit です。

これが初回で機能するかどうかを決めるいくつかの詳細があります:

SSL モードを Auto のままにするか、Disable に設定してください。 Auto では、Casdoor はポート 465 でのみ暗黙的 TLS を使用し、サーバーがそれを提供する場合は STARTTLS でアップグレードします。MailHog もデフォルトの Mailpit もポート 1025 で STARTTLS を提供しないため、接続は平文のままになります。Enable を選択しないでください。これは暗黙的 TLS を強制し、平文テキストサーバーに対するハンドシェイクが失敗します。完全な動作については SSL mode table を参照してください。

認証情報を空のままにしてください。 Casdoor が SMTP サーバーにログインするのは、Username が設定されている場合のみです。これを入力すると、Go の PLAIN 認証はホストが localhost でない限り、未加密接続でパスワードを送信することを拒否するため、192.168.x.x の MailHog は認証エラーで失敗します(MailHog はあらゆるログインを受け入れるにもかかわらず)。Mailpit はデフォルトで認証をまったく要求しません。

正しいホストを使用してください。 127.0.0.1 は、Casdoor とメーキャッチャーが同じマシンで実行されている場合にのみ機能します。両方が Docker Compose で実行されている場合は、サービス名(例えば mailpit)をホストとして使用します。

グローバルプロバイダーを使用してください。 通常の組織が所有するプロバイダーはインターネットアドレスにのみ到達できる可能性があるため、127.0.0.1 やプライベート IP に接続できません。admin または built-in のプロバイダーは制限されていません。Which addresses a provider can reach を参照してください。

リンクのために origin を設定します。 検証コードはすぐに機能します。パスワードリセットリンクおよびマジックリンクは、Casdoor がその公開 URL を認識する必要があります。これは conf/app.conf の origin またはループバックホスト上のリクエストを通じて行われます。そうでない場合、リセットリンクはメールから除外され、マジックリンクは失敗します。Templates を参照してください。

最後に、サインアップとパスワードリセットが実際にそれを使用するように、Add providers to an application でアプリケーションにプロバイダーを追加します。

自動化テストで検証コードを読む​

Casdoor の検証コードは 6 桁で、デフォルトのテンプレートは "Here is your code: " の後にコードが続きます。エンドツーエンドのテストでは、ユーザーをサインアップし、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}`);
}

一度に1件のテストのみがメールを送信する場合、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 の1行の変更で済みます: 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 用に書き換え、items[].Content.Body の代わりに messages[].ID と Text または HTML を読み取ってください。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> ブロックはそのままです:

一般的なセットアップでは、開発環境と CI 環境で Mailpit を使用し、本番環境では実際のプロバイダーを使用します。各環境が異なるプロバイダーを指すようにアプリケーションを設定することで、テストするサインアップフローがそのまま出荷されるものと同じになります。

参考資料​