MailHog vs Mailpit: Casdoorでの確認メールおよびパスワード再設定メールのテスト
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 早見表
| MailHog | Mailpit | |
|---|---|---|
| 最新リリース | v1.0.1, 2020-08-11 | v1.33.0, 2026-10-31 |
| デフォルトブランチでの最終コミット | 2022-08-02 | 2026-10-31 |
| ライセンス | MIT | MIT |
| デフォルト SMTP ポート | 1025 | 1025 |
| デフォルト Web UI および API ポート | 8025 | 8025 |
| Docker イメージ | mailhog/mailhog, amd64 のみ | axllent/mailpit, amd64、arm64 および 386 |
| HTTP API | v1 および v2: list, get, delete, from, to または containing による検索 | v1: list, get, delete, to: や subject: などのフィルターによる検索、latest メッセージショートカット |
| デフォルトストレージ | インメモリ | 一時 SQLite データベース、終了時に削除 |
| 永続的ストレージ | MongoDB または Maildir | SQLite ファイル (MP_DATABASE) または rqlite |
| メッセージ制限 | 記載なし | デフォルトで最新の 500 件を保持 (MP_MAX_MESSAGES) |
| HTML チェック、リンクチェック、スパムチェック | いいえ | はい |
| 新着メールの Webhook | いいえ | はい (MP_WEBHOOK_URL) |
| SMTP TLS | 提供されません | オプションの STARTTLS または SSL/TLS |
| 障害注入 | Jim | Chaos |
| リアルな 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 サーバーです。
- グローバル管理者として、
adminまたはbuilt-in組織にプロバイダーを追加します。 - Category を
Emailに、Type をDefaultに設定します。 - Host をツールが実行されている場所に設定し、Port を
1025に設定します。 - Username と Password は空のままにします。
- 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> ブロックはそのままです:
Defaultタイプの任意の SMTP サーバー(Email providers を参照)- SendGrid および Resend(API 経由)
- Brevo(SMTP リレー経由)
- Azure Communication Services
- Custom HTTP Email を使用した独自の HTTP エンドポイント
一般的なセットアップでは、開発環境と CI 環境で Mailpit を使用し、本番環境では実際のプロバイダーを使用します。各環境が異なるプロバイダーを指すようにアプリケーションを設定することで、テストするサインアップフローがそのまま出荷されるものと同じになります。
参考資料
- MailHog リポジトリと README: https://github.com/mailhog/MailHog
- MailHog 設定および API v1/v2 ドキュメント: https://github.com/mailhog/MailHog/tree/master/docs
- MailHog メンテナンスに関するコメント: https://github.com/mailhog/MailHog/issues/442#issuecomment-1493415258
- Mailpit リポジトリと README: https://github.com/axllent/mailpit
- Mailpit ドキュメント (Docker, storage, SMTP, webhook, search filters): https://mailpit.axllent.org/docs/
- Mailpit API v1 リファレンス: https://mailpit.axllent.org/docs/api-v1/
- Casdoor メールプロバイダーコード: https://github.com/casdoor/casdoor/tree/master/email