👏

playwrightでMailtrapのapiからメール本文を取得する

2023/07/12に公開

やりたいこと

playwrightのテスト内でMailtrapのAPIを叩いて、メール本文を取得し、メールが正しく送信されているかを確認する

背景

自分が使っている環境ではメールは登録されたメアドに飛ばさずに、全てMailtrapに飛ぶようにしている。
e2eテストでメールに記載のURLにアクセスしたくなった。
が、Mailtrapにログインさせるのは避けたいので、apiを叩いてみた。

使用技術

・playwright
・Mailtrap

参考記事

受信メールの検証、MailTrap
Mailtrap公式
Playwright公式

手順

1. API Tokenを取得する

MailTrapにログイン後、API Tokenを取得します。
(画面右上の自分のアカウント名が書かれている箇所をクリック後、MyProfileから確認できます。)

2.Account IDを取得する

settingsのAccount settingsにアクセスし、Account IDを取得します。

3.Inboxのidを取得する

MailTrapのAPIDocsから対象のInboxのidを取得します。
画像右上の黒い箇所に適切なAPI-Tokenとaccount_idを入れて、"Send API Request"をクリックすると後述のResponseが返ってきます。

[
  {
    "id": 3538,
    "name": "Admin Inbox",
    "username": "b3a87978452ae1",
    "password": "6be9fcfc613a7c",
    "max_size": 0,
    "status": "active",
    "email_username": "b7eae548c3-54c542",
    "email_username_enabled": false,
    "sent_messages_count": 52,
    "forwarded_messages_count": 0,
    "used": false,
    "forward_from_email_address": "a3538-i4088@forward.mailtrap.info",
    "project_id": 2293,
    "domain": "localhost",
    "pop3_domain": "localhost",
    "email_domain": "localhost",
    "emails_count": 0,
    "emails_unread_count": 0,
    "last_message_sent_at": null,
    "smtp_ports": [
      25,
      465,
      587,
      2525
    ],
    "pop3_ports": [
      1100,
      9950
    ],
    "max_message_size": 5242880,
    "permissions": {
      "can_read": true,
      "can_update": true,
      "can_destroy": true,
      "can_leave": true
    }
  }
]

(こんなめんどくさいことせずとも、任意のInboxのurlに含まれている数字がinboxIdです!)

4.inboxに保存されているメール一覧を取得する

再び、API Docsからメッセージ一覧を取得するAPIRequestを確認します。
今回はGet messagesから確認しました。
それをコードに落とし込むと以下のようになります。

import { request, APIRequestContext } from "@playwright/test";

const MailtrapApiToken = process.env.MAILTRAP_API_TOKEN;
const mailtrapAccountId = process.env.MAILTRAP_ACCOUNT_ID;
const mailtrapInboxId = process.env.MAILTRAP_INBOX_ID;

export async function getMail() {
  const mailtrap: APIRequestContext = await request.newContext();

  const response = await mailtrap.get(
    `https://mailtrap.io/api/accounts/${mailtrapAccountId}/inboxes/${mailtrapInboxId}/messages`,
    {
      headers: {
        Accept: "application/json",
        "Api-Token": MailtrapApiToken,
      },
    }
  );
}

コードの解説

Tokenなどは秘匿情報になるので、環境変数に入れています。

const MailtrapApiToken = process.env.MAILTRAP_API_TOKEN;
const mailtrapAccountId = process.env.MAILTRAP_ACCOUNT_ID;
const mailtrapInboxId = process.env.MAILTRAP_INBOX_ID;

playwrightで何を操作するかを明記しています。(ここはほぼおまじないなので、よくわからず。)

const mailtrap: APIRequestContext = await request.newContext();

responseをresponse定数に代入しています。

  const response = await mailtrap.get(
    `https://mailtrap.io/api/accounts/${mailtrapAccountId}/inboxes/${mailtrapInboxId}/messages`,
    {
      headers: {
        Accept: "application/json",
        "Api-Token": MailtrapApiToken,
      },
    }
  );

5.responseから特定のメールを検索する

今回使っているinboxは自分だけ使っているだけではないので、1番最初のメッセージが自分が送ったメッセージとは限りません。
そのため、今回は「題名」と「メアド」で検索して、任意のメッセージを取得します。

~~中略~~
`https://mailtrap.io/api/accounts/${mailtrapAccountId}/inboxes/${mailtrapInboxId}/messages`,
    {
      headers: {
        Accept: "application/json",
        "Api-Token": MailtrapApiToken,
      },
    }
  );
  const messageResponse = await response.json();
  const targetMail = messageResponse.find(
    (data) => data.subject === "ホゲホゲ" && data.to_email === "hogehoge@hoge.hoge"
  );
 }

コード解説

レスポンスの本文をJSON形式として解析し、JavaScriptのオブジェクトとして返します。JSON形式の解析に成功すると、解析結果のオブジェクトがmessageResponseに格納されます。

const messageResponse = await response.json();

messageResponseに格納されているjsonから題名が「ホゲホゲ」で「hogehoge@hoge.hoge」に送られているメッセージを検索し、targetMailに格納しています。

const targetMail = messageResponse.find(
    (data) => data.subject === "ホゲホゲ" && data.to_email === "hogehoge@hoge.hoge"
);

6.本文を取得する

先ほど検索したjsonのデータからidを取得し、再びAPIを叩きます。
APIはAPI DocsのGet text messageから確認できます。

~~中略~~
  const targetMail = messageResponse.find(
    (data) => data.subject === "ホゲホゲ" && data.to_email === "hogehoge@hoge.hoge"
  );
  const targetMailId = targetMail.id;
  const targetMailText = await mailtrap.get( `https://mailtrap.io/api/accounts/${mailtrapAccountId}/inboxes/${mailtrapInboxId}/messages/${targetMailId}/body.txt`,
    {
      headers: {
        Accept: "application/json",
        "Api-Token": MailtrapApiToken,
      },
    }
  );
  const messageText = await targetMailText.text();
  return messageText;
}

コード解説

targetMailに格納されているjsonからidを取得し、targetMailIdに格納しています。

const targetMailId = targetMail.id;

get text messageから取得したresponseをtargetMailTextに格納しています。

const targetMailText = await mailtrap.get( `https://mailtrap.io/api/accounts/${mailtrapAccountId}/inboxes/${mailtrapInboxId}/messages/${targetMailId}/body.txt`,
    {
      headers: {
        Accept: "application/json",
        "Api-Token": MailtrapApiToken,
      },
    }
  );

targetMailTextに格納しているjsonをtextとして取得します。

const messageText = await targetMailText.text();

最後にmessageTextを返すことで、呼び出し元のテストコードで使用できます。

return messageText;

コード全体

import { request, APIRequestContext } from "@playwright/test";

const MailtrapApiToken = process.env.MAILTRAP_API_TOKEN;
const mailtrapAccountId = process.env.MAILTRAP_ACCOUNT_ID;
const mailtrapInboxId = process.env.MAILTRAP_INBOX_ID;

export async function getMail() {
  const mailtrap: APIRequestContext = await request.newContext();
  const response = await mailtrap.get( `https://mailtrap.io/api/accounts/${mailtrapAccountId}/inboxes/${mailtrapInboxId}/messages`,
    {
      headers: {
        Accept: "application/json",
        "Api-Token": MailtrapApiToken,
      },
    }
  );
  const messageResponse = await response.json();
  const targetMail = messageResponse.find(
    (data) => data.subject === "ホゲホゲ" && data.to_email === "hogehoge@hoge.hoge"
  );
  const targetMailId = targetMail.id;
  const targetMailText = await mailtrap.get( `https://mailtrap.io/api/accounts/${mailtrapAccountId}/inboxes/${mailtrapInboxId}/messages/${targetMailId}/body.txt`,
    {
      headers: {
        Accept: "application/json",
        "Api-Token": MailtrapApiToken,
      },
    }
  );
  const messageText = await targetMailText.text();
  return messageText;
}

使用例

自分は最後のテキストからURLを取得して、取得したURLにアクセスしテストを続けています。

~~中略~~
  const messageText = await targetMailText.text();
  // textからURLを取得する操作
  const urlRegex = /https?:\/\/[\w-]+(\.[\w-]+)+([^\s]*)+/g;
  const url = messageText.match(urlRegex)[0];
  return url;
 }

呼び出し元

const url = await getMail();
// 文面から取得したURLに移動
await page.goto(url);

最後に

jsonで受け取った後からは、こちらで好き勝手できるものなので、適宜好きにいじってみてください。
playwrighとmailtrapを使用した記事が見つからなかったので、今回作成しました。
少しでもお力になれれば幸いです!

COUNTERWORKS テックブログ

Discussion