ネットワークスイッチに接続された青いイーサネットケーブル
ニュース深掘り

使い捨てメール受信ボックスでEメール統合テストを実現する

目次を見る

モックで transport.send が呼ばれたことを確認して「テスト完了」とする――メールのテストはそこで止まりがちです。しかし送信路のモックは、テンプレートが {{user.name}} をそのまま文字列として出力していてもグリーンを返します。受信路のアサーションが欠けている以上、外部に向けて非同期で通信するその経路は、システムの中でもっともカバレッジが薄い箇所になります。

なぜメールテストは「受信側」が難しいのか

メールテストの本質的な難しさは送信ではなく、届いたメッセージの内容を検証することにあります。実際にメールが届いたか、本文のリンクが正しいか、OTPトークンが含まれているかを確認するには、テストランナーから読み書きできるリアルな受信ボックスが必要です。

よく使われる回避策としては、まずモックがあります。これは高速ですが、実際にメールが送信されたかどうかは何も証明しません。次に共有のGmail/Outlookテストアカウントという方法があります。リアルなメールを扱えますが、並列CIワーカーが同じ受信ボックスを読みに行くため競合が起きやすく、OAuthのリフレッシュトークンが有効期限切れになるリスクも伴います。ワイルドカードドメインのcatch-allアドレスも選択肢に挙がりますが、受信ボックスが共有のままであることには変わりません。

エフェメラルなAgent Accountという発想

NylasというメールAPIプラットフォームが提供するAgent Account(エージェントアカウント)は、この問題への一つのアプローチです。Nylasは「Nylas Email API」として知られ、GmailやMicrosoft 365などのメールプロバイダーと自社アプリを繋ぐ統合APIを提供しています。

Agent AccountはひとことでいうとOAuthフローなしで作成できる使い捨てのメールボックスです。通常のGoogleアカウント連携では人間がブラウザでOAuth同意画面を操作する必要があります。しかしAgent Accountは1回のAPIコールだけでプロビジョニングでき、テスト終了後にも1回のAPIコールで削除できます。作成されたメールアドレスは ci-run-8842@agents.yourcompany.com のように実際に外部からメールを受信でき、送信も行えます。

技術的な実体としては grant_id を持つNylasグラントです。グラントとはNylasがメールボックスへのアクセス権をトークン形式で管理する単位で、GET /v3/grants/{grant_id}/messages のように既存のNylas APIエンドポイントをそのまま使えます。新しいエンドポイントを覚える必要がない点が設計上の利点の一つです。

CIパイプラインでの典型的な使い方は以下のような流れになります。

# テスト開始時にAgent Accountを作成
nylas agent-accounts create --domain agents.yourcompany.com
# => { "grant_id": "ci-run-8842", "email": "ci-run-8842@agents.yourcompany.com" }

# テスト終了時に削除
nylas agent-accounts delete --grant-id ci-run-8842

このパターンをJest/Vitestのglobalセットアップとteardownに組み込めば、テストスイートごとに独立した受信ボックスを用意できます。

テスト設計の観点から見た構造的アイソレーション

テスト設計においてアイソレーション(隔離)は重要な性質です。並列テストが互いに干渉しないためには、共有リソースへのアクセスを避けるか、アクセスをテストごとに分離する必要があります。

Agent Accountが提供するのは「フィルターによる分離」ではなく「構造的な分離」です。共有受信ボックスを件名フィルターで切り分ける方法は、フィルター条件の衝突や漏れが常に起こりえます。一方、テストごとに別の grant_id を持つ独立したメールボックスを割り当てれば、並列ワーカー間の競合はそもそも発生しません。

類似のアプローチとして、Mailhog(ローカルのSMTPモックサーバー)やMailtrap(SaaSのメールテストサービス)があります。Mailhogはローカル開発やDockerコンテナ内での利用に向いていますが、外部からの実際のメール受信は行えません。MailtrapのSandbox機能も受信テストを提供しますが、ワーカーごとに受信ボックスを動的に生成・削除するAPIは限定的です。Agent Accountのアプローチが差別化できる点は、実際の外部MTAからのメール受信と、プログラマブルなライフサイクル管理の組み合わせにあります。

なお、シード記事では「新しいドメインの配信ウォームアップには約4週間かかる」と明記されています。これはIPレピュテーション(メールサーバーの信頼スコア)の問題で、新しいドメインからのメールはスパムフォルダに振り分けられやすいため、本番環境と同等の到達率を確保したい場合はドメインの準備に時間的余裕が必要です。

  • 送信モック: 速いが実際の送信・レンダリングを検証できない
  • 共有テストアカウント: リアルなメールだが並列テストで競合が起きる
  • catch-allドメイン: 共有受信ボックスのため隔離が弱い
  • Agent Account: 動的生成・削除、実際の外部受信、構造的アイソレーションを兼ねる

メールの統合テストが長らく「テストしない」で済まされてきた背景には、適切なフィクスチャ(テストの前提状態を作る仕組み)が存在しなかったという技術的制約があります。使い捨てメールボックスをプログラムで管理できる環境が整いつつある今、受信路のアサーションをCI上で実現するハードルは以前より低くなっています。

参考

Spin up ephemeral test inboxes for email integration tests

この記事について: 本記事は AI を活用して作成し、forva AI 編集部が内容を確認・監修しています。

AI 駆動開発のご相談は forva AI へ。まずはお気軽にどうぞ。