---
title: "Playwright でメール OTP ログインをテストする：既存の受信箱を使う手順"
description: "Playwright でメール OTP ログインをテストする手順。既存の Gmail・Outlook を使い、期限付き待機、古いコードの除外、CI の秘密情報管理まで説明します。"
url: https://mailera.app/ja/blog/playwright-email-otp
published: 2026-10-25
updated: 2026-10-25
---

# Playwright でメール OTP ログインをテストする：既存の受信箱を使う手順

自分が管理するテスト用メールボックスを Mailera に接続し、認証メールの取得からログイン成功の確認までを Playwright に組み込みます。

## メール OTP と TOTP は分けて考えます

メール OTP は、メールで届く使い捨ての認証コードです。Playwright のメール認証自動化では、コードの取得だけでなく、入力後に認証が成立したことまで確認します。

| 方法 | コード・状態の取得元 | 検証する範囲 | 本記事での扱い |
| --- | --- | --- | --- |
| メール OTP | テスト用メールボックス | メール送信から受信、入力、ログインまで | 対象です |
| TOTP | 認証アプリなど | 時間ベースのコードによる認証 | 生成手順は扱いません |
| 認証済み状態の再利用 | 保存したログイン状態 | ログイン後の機能 | メール認証経路の代用にはしません |

[Mailera の仕組み](https://mailera.app/ja/product)は、既存のメールボックスを API につなぐものです。接続構成の全体像は[既存メールプロバイダーを接続するガイド](https://mailera.app/ja/blog/connect-existing-email-to-agents)、取得の基本は自分の受信箱から OTP を読む手順を参照してください。

![Playwright の送信要求から、既存メールボックスでの受信、API 取得、コード入力、ログイン成功確認までの流れ](https://mailera.app/media/1d9d465ff8c4abdb/playwright-otp-otp-flow-ja-1200.jpg)
_メールの取得とログイン成功の判定は別の処理です。配送と同期を待つ期限も設けます。_

## テスト前の準備

1. 自分が管理するアプリと、テスト専用メールボックスを用意します。通常業務のメールが届く個人用受信箱は使いません。
2. プロバイダー別の手順に沿ってテスト用メールボックスを接続します。Outlook・Microsoft 365 の接続条件は、[Microsoft の接続手順](https://mailera.app/ja/providers/microsoft)と[Microsoft 365 の Graph 設定チェックリスト](https://mailera.app/ja/blog/microsoft-365-graph-mail-setup)で確認してください。
3. 「設定」の「API key」タブから「キーを作成」を開き、「メールボックスのスコープ」をテスト用グループに限定します。読み取り権限（`read`）を選び、「有効期限」も設定します。キーは一度しか表示されないため、その場で CI のシークレットに保存します。

Gmail の接続は [Gmail の接続ガイド](https://mailera.app/ja/providers/gmail)を使ってください。Mailera ではアプリパスワード（app password）を使います。[Google のアプリパスワードの説明](https://support.google.com/accounts/answer/185833)では、利用条件として 2 段階認証の有効化が示されています。

![テスト専用グループへの範囲限定と読み取り権限を設定する Mailera の API キー作成画面](https://mailera.app/media/acddf0c7116963a2/playwright-otp-read-key-ja-1200.jpg)
_OTP の取得には read 権限を使い、テスト対象以外のメールボックスをキーの範囲から外します。_

接続後は `GET /mailboxes` を呼び、`data` 内の対象メールボックスの `status` と `last_sync_at` を確認します。Mailera の新着確認の頻度はメールボックスの状態によって変わります。リアルタイム監視に対応する場合は使用中に数秒以内で新着を検知し、対応しない場合は使用中に 2 分ごとに確認します。未使用のメールボックスはスリープする場合があります。送信直後に読めることを前提にせず、待機処理を組み込みます。

## Playwright からコードを取得して入力する

`GET /mailboxes/{id}/otp` は最新の OTP を取得する `read` 権限の API です。`from`、`subject`、`since_minutes` で対象を絞れます。ただし、最新であることと、今回のログイン要求に対応することは別です。

以下の例では、コードだけでなく受信日時と件名を確認し、候補が複数あれば失敗させるため、`GET /messages/search` に `extract=otp` を指定します。検索 API には `mailbox`、`from`、`since` を渡し、返された各メッセージの `subject` を TypeScript 側で `OTP_SUBJECT` と完全一致で比較します。検索 API に `subject` パラメーターは渡しません。コードは `data` 内の各メッセージの `otp.code` から読みます。

最新コードの取得には `/mailboxes/{id}/otp`、メッセージ情報を使って候補を選別するこのテストには `/messages/search` を使う、という使い分けです。API の入口は [開発者向けページ](https://mailera.app/ja/developers)、各操作は [API ドキュメント](https://mailera.app/ja/docs)にあります。

### 送信前に環境変数を設定する

`@playwright/test` が導入済みの既存の TypeScript テストプロジェクトで、次の値を環境変数に設定します。

| 変数 | 内容 |
| --- | --- |
| `MAILERA_API_KEY` | テスト用グループに限定した `read` キー |
| `MAILBOX_ID` | 接続したテスト用メールボックスの ID |
| `TEST_APP_URL` | 自分が管理するアプリのログイン画面 URL |
| `TEST_EMAIL` | そのアプリに登録したテスト用メールアドレス |
| `OTP_FROM` | 認証メールの送信元アドレス |
| `OTP_SUBJECT` | 認証メールの件名全文 |

### 期限付きの取得ヘルパーを用意する

次を既存のテストプロジェクト内の `otp-helper.ts` に保存します。待機期限の 60 秒と確認間隔の 3 秒は、この例の設定値であり、到着時間の保証ではありません。リアルタイム監視に対応しないメールボックスでは確認間隔が 2 分のため、アプリ側のコード有効期限も踏まえて待機期限を調整してください。候補が複数ある場合は、コードを推測して選ばず失敗させます。

```ts
import type { APIRequestContext } from '@playwright/test';
export async function waitOtp(api: APIRequestContext, started: number) {
  const deadline = Date.now() + 60_000;
  while (Date.now() < deadline) {
    const res = await api.get('https://mailera.app/api/public/v1/messages/search', { timeout: Math.min(5000, deadline - Date.now()), params: {
      mailbox: process.env.MAILBOX_ID!, from: process.env.OTP_FROM!, since: new Date(started).toISOString(),
      extract: 'otp', limit: 20 } });
    if (!res.ok()) throw new Error(`Mailera HTTP ${res.status()}`);
    const { data } = await res.json();
    const matches = data.filter((m: { subject: string; received_at: string; otp?: { code: string } }) => m.subject === process.env.OTP_SUBJECT && Date.parse(m.received_at) >= started);
    if (matches.length > 1) throw new Error('認証メールの候補が複数あります');
    if (matches[0]?.otp?.code) return matches[0].otp.code;
    await new Promise(resolve => setTimeout(resolve, Math.min(3000, Math.max(0, deadline - Date.now()))));
  } throw new Error('認証メールの待機期限に達しました');
}
```

候補がなければ再確認します。HTTP エラーや通信エラーは未着として扱わず、その時点で終了します。コードやレスポンス本文はエラーメッセージに含めません。

### 既存のログインテストに組み込む

ヘルパーは単独で実行せず、既存の Playwright テストから呼び出します。画面要素は対象アプリに合わせ、次の順序で処理します。

1. Mailera 専用の `APIRequestContext` を作成します。`baseURL` は `https://mailera.app/api/public/v1`、認証ヘッダーは `Authorization: Bearer $MAILERA_API_KEY` とし、環境変数の実際の値を渡します。上のヘルパーは取得先を完全な URL で指定しているため、`baseURL` の末尾の `/` に依存しません。認証ヘッダーを対象アプリへの通信に混在させません。
2. ログイン画面を開いてテスト用メールアドレスを入力します。コード送信を要求する直前に `Date.now()` を記録し、`started` として保持します。
3. 送信要求後に `waitOtp(api, started)` を呼び、返されたコードを認証コード欄へ入力します。テスト全体の制限時間は、ヘルパーの待機時間に画面操作と成功確認の時間を加えて設定します。
4. ログイン操作を行い、認証後だけ表示される要素で成功を検証します。コードを取得できたことだけでテストを成功させません。
5. 成否にかかわらず、`finally` で Mailera 専用コンテキストの `dispose()` を呼びます。

このテストは自動再試行なしで扱い、同じメールボックスを別の CI ジョブでも同時に使わないでください。

## 古いコードや別テストのコードを避ける

直列実行だけでは、前回のメールを除外できません。`since_minutes` も相対的な時間範囲であり、ログイン要求の識別子ではありません。

上の例は送信要求の直前の時刻、送信元、件名を使います。それでも、前回要求したメールが遅れて届けば候補に入る余地があります。厳密に対応付けるなら、テスト対象アプリ側で実行ごとの識別子を件名などに入れ、`OTP_SUBJECT` にその件名を渡す設計にします。

調査には `GET /mailboxes/{id}/messages` の `received_at` と `id`、必要に応じて `GET /mailboxes/{id}/messages/{msgId}` の本文を使います。件名は `subject`、送信元は `from.address` を確認し、今回の要求に対応するメールか照合してください。候補が多い場合は `next_cursor` による続きを確認する設計も必要です。上の短い例は、専用メールボックスで候補を少なく保つ前提です。

## メールが届かない・認証に失敗する場合の確認

未着時は、まず `GET /mailboxes/{id}/status`、次に `GET /mailboxes/{id}/placement`、最後に受信トレイと迷惑メールの実際のメッセージを確認します。`status` は Microsoft ではサインインを直接確認し、ほかのプロバイダーでは最新の同期に基づく状態を返します。

| 症状 | 確認箇所 | 次の操作 |
| --- | --- | --- |
| メールボックスに接続できない | `status` と接続情報 | 接続を復旧してから再実行します |
| アプリは送信したが見つからない | `placement` と迷惑メール | 実際の保存先を確認します |
| メールはあるが候補にならない | 送信元、件名、受信日時 | 実際のメールと条件を照合します |
| コードを入力しても失敗する | アプリ側の有効期限・再送仕様 | 期限切れや旧コードの無効化を調べます |
| 待機期限に達する | 接続状態と同期状態 | 診断情報を残して失敗させます |

Gmail でアカウントのパスワードを変更した場合は、[Google が説明するアプリパスワードの失効](https://support.google.com/accounts/answer/185833)も確認してください。

明示的な同期には `POST /mailboxes/{id}/sync` と `sync` 権限が必要です。通常の `read` キーに無条件で追加せず、接続準備の操作として分けます。未着のたびにコードを再送するループも作りません。

Mailera は即時到着や受信トレイへの振り分けを保証しません。「迷惑メールではない」で移動しても、次回の振り分けを決めるのはプロバイダーです。また、コードの有効性は対象アプリが判定します。API でコードを取得できただけでは、ログインテストは成功していません。

## CI で API キーと認証コードを漏らさないための設定

キーは CI のシークレットからテストプロセスに渡し、ソースコードやブラウザー側に埋め込みません。GitHub Actions を使う場合は、[公式のシークレット利用手順](https://docs.github.com/en/actions/how-tos/write-workflows/choose-what-workflows-do/use-secrets)に沿って、`secrets` コンテキストから環境変数へ渡します。有効期限と失効担当を決めておきます。Mailera のキーを失効すると、そのキーを使う API 呼び出しは直ちに拒否されます。

メール OTP のテストでは、スクリーンショット、動画、トレースを無効にしてください。カスタムレポーターや HTTP デバッグログも別途確認し、認証ヘッダー、コード入力値、メール本文を出力しない設定にします。診断用の画像を残す場合は秘密情報を伏せ、保存先と閲覧権限を限定します。

メール本文は信頼できない入力として扱います。必要なコード以外を実行せず、本文に書かれた任意の指示やリンクにも従いません。運用上の確認には [Mailera のセキュリティ情報](https://mailera.app/ja/security)も参照してください。

**APIで同じ操作を実行** — この記事の操作はすべてREST APIで実行できます。curlの例、API key、webhookも利用できます。 [APIドキュメントを見る](https://mailera.app/ja/docs)
