テストで、配信事故を起こさない＆不自由なくテストできる環境の作り方

この記事は、[メール Advent Calendar 2018](https://qiita.com/advent-calendar/2018/mail) 8日目のものです。

# そもそも、テストのメール配信事故ってなに？

様々なインターネット用のシステムで欠かせないメールの送信。テストでも実施すると思います。ところが、不用意なテストの実施で送ってはいけない先にメールを送ったり、テストの不足によって本番になってメールを送信できなかったり、とトラブルが発生することがあります。これを**テストのメール配信事故**と呼んでみます。
※もっと良い呼び名があるかもしれない。
下記のようなパターンがあるかと思います。

## 第三者に送信

例えば、ECサイトのテスト環境の会員データを hoge@abc.com とか fuga@test.com など、適当なメールアドレスで作ります。テスト環境で決済するたびに hoge@abc.com に決済完了のメールが飛んでいくのですが、abc.com はアメリカ ABC News のドメインであり、メールがインターネットを介して関係のない第三者の（しかもアメリカの）メールサーバーに飛んで行ってしまいます。

## 自社のサーバーに大量送信

今度は、ECサイトのテスト環境の会員データを notexists-連番@自社のドメイン.co.jp と設定すれば、少なくとも、数通であれば問題になることは（たぶん）ないと思います。ところが、バッチの中で処理対象だった会員へ大量に送ることになり、数千通や数万通送ってしまったら話は別です。
メールサーバーが自社のオンプレミスであれば、サーバーに負荷がかかり、メールサーバーの管理者が激オコでやってくるでしょう。メールサーバーがGsuiteやoffice365などクラウドであれば、クラウド側で遮断されて、やっぱりメールサーバーの管理者が激オコでやってきます。

## 携帯キャリアやWEBメールサービスあてに一字間違えて送信

「Gmailからリンクを踏んだときだけ挙動がおかしい」「ドコモメールからリンクを踏んだときだけ表示が崩れる」そんなどうして？な問い合わせも、ときたまあります。
こういうとき、Gmail,yahoo,outlook.comやdocomo,au,softbank にまずテストのURLを含んだメールを送るのですが、このような多数のユーザーを抱えるWEBメールサービス(MBP=MailBox Provider)や携帯キャリアは、宛先を一字間違うと見ず知らずの人に届く可能性があります。

## 配信のテストしないでサービスインして誤り発覚

このようにテストでのメール配信事故はしばしば発生します。その反応として、テスト環境ではメールを一切送らないようにネットワークレベルで遮断した、という環境もあると思います（ファイアウォールなどで外行き25番を全部drop、とか）。こうすると、今度はメールの見た目を確認しなかったなど、メール関連のテストができずにリリース/サービスインし、その後誤りが発覚することがあります。

# 事故は起こしたくない、されど、テストはしたい

こんなふうに、メール送信という処理、テスト実施は不可欠ですが、環境を整備せずに一歩間違うと事故ります。そこで、**テスト担当者が一歩間違ったくらいでは事故にならず、かつ、メール送信関連の充分なテストができる環境を構築する方法**、を書きます。
（前置き長い……すみません）

# 対応1.生成するメールアドレスに気をつける

サイトのテスト会員用にメールアドレスを設定する、どこでも行われます。このとき、メールを送る目的がなければ、**ユーザー名@example.com、ユーザー名@example.net、ユーザー名@example.org** に設定します。
これら、

- example.com
- example.net
- example.org

は、[RFC2606](https://tools.ietf.org/html/rfc2606)、[RFC2606日本語訳](http://pentan.info/doc/rfc/j2606.html) で、例示/実験用として定められていて、届くことがありません。
※いま、確認したら、MXレコードなし、Aレコードあり、そのAレコードの25番にアクセスしても無反応。

これら例示用ドメインに送ろうとすること自体良くないのですが、それでも hoge@実在するドメイン、に送信するよりずっとましです。
まずは安全策として、テストの会員データや設定ファイルのサンプルに書くメールを送る目的のないメールアドレスは、このexampleドメインのメールアドレスで設定します。

# 対応2.テストの受信サーバーを立てよう

とはいえ、メールを送り、その内容を確認したいこともあります。このようなとき、テスト担当者の自社のメールアドレスを宛先に設定する場合が多いと思います。しかし、これでは「自社のサーバーに大量送信」の事故を防ぐことができません。
そこで、テスト用のドメインを取得し(自社：example.com → テスト受信用ドメイン：junk.example.com)、postfix(+dovecot) などでテスト用メールサーバーを立てて、そこで受信だけ行います。
受信だけすればいいので、中継は一切行わないようにします。(postfixなら mydestination だけ書いて、mynetworks が空)

ここまで準備し、テストでのメール送信先が fuga@junk.example.com とテスト用ドメインあてになるよう、テスト環境の会員メールアドレスなどを設定します。

こうしたときも何かの間違いで、テスト用メールサーバーにメールが大量に送られてしまうことがあるかもしれません。その結果、テスト用のメールサーバーに負荷がかかり配送が遅延するかもしれません。それでも、自社のメールを同様の障害に巻き込みよりずっとましです。

# 対応3.送信用のサーバーで宛先を書き換える（postfix用）

※postfix 以外でこれができるかは知らないので、知っていたら教えてください。（商用サービスならありそうだし知ってる）
最後に残ったケースとして、携帯キャリアやWEBメールサービスに送ってテストしたい、があります。一字間違うと他人に届くよね、というあれです。

この場合、送信用のMTAに postfix を使っていれば、このようにして特定の宛先以外をゴミ箱に捨て去ることができます。

/etc/main.cf に追記
> local_header_rewrite_clients = permit_inet_interfaces, permit_mynetworks
> canonical_classes = envelope_recipient
> recipient_canonical_maps = regexp:/etc/postfix/recipient_canonical.regexp

/etc/postfix/recipient_canonical.regexp (新規作成)
> \# 対応2.のテスト用のドメインあては全部通す
> /^(.*)@junk\\.example\\.com\$/ $1@junk.example.com
>
> \# 携帯キャリアなど特定ドメインの特定のユーザーだけ通す
> /^hoge@example\\.net\$/ hoge@example.net
> /^fuga@example\\.org\$/ fuga@example.org
>
> \# 上にはてはまらない宛先はこのサーバーのゴミ箱に捨てる
> \# 事前に adduser trash などメールボックスを作っておく
> /^(.*)$/        trash@(このサーバーのmydestinationなFQDN)

ここで使用しているのは、postfix のアドレス書き換えという機能です。
-Postfixアドレス書き換え-
http://www.postfix-jp.info/trans-2.3/jhtml/ADDRESS_REWRITING_README.html

このように設定することで

| 元の宛先              | 届く宛先              |
|:--------------------:|:--------------------:|
| ***@junk.example.com | ***@junk.example.com |
| hoge@example.net     | hoge@example.net     |
| fufa@example.net     | trash@このサーバー    |
| hoge@example.org     | trash@このサーバー    |
| fuga@example.org     | fuga@example.org     |
| 無関係なドメイン     | trash@このサーバー   |

と届く宛先を変えることができます。
また、書き換えるのは Envelope-To で ヘッダTo は書き換えないので、trashあてメールをPOP3などで取得すれば、どんな宛先に送ろうとして、送ることなくゴミ箱行きになったかを把握することができます。