いますぐ使う Mailgun

Amazon SES はクラメソさんの初期構築の記事が充実してたり、オンプレなら Postfix 立ててな太古の記事がいくつも見つかりますが、 Mailgun や SendGrid の記事のググラビリティが低いように思いました。なので書いてみました。

私自身は、

* 自宅サーバーで Postfix & Dovecot を構築運用したことがある
* お仕事で Postfix リレーサーバー & Amazon SES にリレー を構築運用したことがある
* お仕事で Amazon SES から Mailgun に移行したことがある
* Mailgun以外の、SendGridとかMailChimpとか、お仕事では使ったことない

くらいの人です。

# Mailgun いいぞ

「いいぞ」を実感として持っているMailgunのいいところ。自前PostfixやAmazon SESとの比較を念頭に。

* 初期構築が簡単
    * アカウント開設、クレカ登録、Mailgun設定、DNS設定、アプリケーション側設定。もうメール送信できる
* ログのビューワーが存在していて、自前で作らなくていい
* ログのビューワーから、メールの再送ができて、自前で作らなくていい
* バウンス管理機能 & 苦情管理機能が存在していて、自前で作らなくていい
* 管理者以外の権限でユーザー発行できる
    * エンジニア以外の方、たとえばカスタマーサポートチームにトラブルシュートを移譲できる

SendGridとかMailChimpとかも、だいたい同じような機能を持ってます。

# Mailgunつらいぞ

* RFC準拠していないメアドに容赦ない
    * アプリケーションから送っても、Mailgunが受け取ってくれず、Mailgunのログに残らないケースがある
* 単純にAmazon SESの4倍くらい高価
* UIが、そこそこモッサい、重い

# 前準備

自前のドメインを取得しておいてください。お名前comでも、Route53でも、何でもよいです。

# アカウント開設

https://www.mailgun.com/

`Add payment info now` のチェックを外せば、クレカ入力不要でアカウント開設できます。 

<img width="707" alt="スクリーンショット 2019-12-17 22.27.04.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22947/6b6529a2-e1bb-15fb-4e1a-1ea05fdfb63d.png">

アカウント開設すると、確認メールが届きます。

<img width="646" alt="スクリーンショット 2019-12-17 22.29.58.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22947/0b1c6cdd-0e5f-5a3b-b24a-f12fa53d48e4.png">

確認メールのリンクを踏むと、電話認証です。英語を話せなくても大丈夫です。SMSで番号を送られてくるだけです。 `Send verification code` 。

<img width="521" alt="スクリーンショット 2019-12-17 22.30.26.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22947/501c031c-8671-3fb2-7760-d8964f6b8414.png">

送られてきた認証コードを入力しましょう。

<img width="517" alt="スクリーンショット 2019-12-17 22.31.01.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22947/3b3d9438-3c99-353c-5115-e46d8b384950.png">

# Sandboxから送信

ようやくダッシュボードに入れました。画面下側? 右側? の `Try Now` に、Sandbox経由であなた宛にだけ送る、サンプルコードがいくつかの言語で出てますので、勢いでやってみましょう。

<img width="932" alt="スクリーンショット 2019-12-17 22.43.36.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22947/2a19ee75-847b-a32e-a4b2-dd27e2a994c1.png">

最強てっとりばやいcURLで。

```bash
$ curl -s --user 'api:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' \
>  https://api.mailgun.net/v3/sandboxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.mailgun.org/messages \
>  -F from='Mailgun Sandbox <postmaster@sandboxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.mailgun.org>' \
>  -F to='Shinnosuke Suzuki <sasasin@sasasin.net>' \
>  -F subject='Hello Shinnosuke Suzuki' \
>  -F text='Congratulations Shinnosuke Suzuki, you just sent an email with Mailgun!  You are truly awesome!'
{
  "id": "<20191217134920.1.BA5676C6F3C92DCC@sandboxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.mailgun.org>",
  "message": "Queued. Thank you."
}
```

受信できれば成功です。

<img width="641" alt="スクリーンショット 2019-12-17 22.51.12.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22947/65cef6df-fd31-91f0-78b2-2078a25c1c80.png">

# クレカ登録

スパマー対策として、クレカ登録しないと、これ以上のことはできないようになってます。クレカ登録するぞ。どこのページからでもいいのですが `Upgrade` からクレカ登録できます。

<img width="930" alt="スクリーンショット 2019-12-17 22.55.51.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22947/f545621a-ce55-baa0-4e7b-5292a569e19e.png">

`Billing address` は何かテキトーに埋めればいいです。

<img width="928" alt="スクリーンショット 2019-12-17 22.59.35.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22947/898660be-22c7-6dec-1b29-a187ddcc8b0e.png">

これでSandboxじゃないドメイン作成ができるようになります。

# ドメイン作成

Mailgunでは送信元ドメインごとに管理します。ドメイン設定を作成しましょう。

Sending -> Domains -> Add new domain

<img width="1373" alt="スクリーンショット 2019-12-17 23.04.32.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22947/c419b228-8d15-a110-e6e2-3ca87a4361be.png">

私が持ってる `sasasin.net` から送ることにしたいので、そのように登録します。諸事情(開封追跡とかメール受信とか)からサブドメインを掘ることを推奨されてるので、すなおに `mg.sasasin.net` として作成します。
EUとUSで分かれてるのは、たぶんGDPRが絡んでるのかな(知らん)。

DKIMは 1048 bitで作りました。Route53にDKIMを登録しようとしたら、2048bitのは `Too long` だって登録できませんでした....。

`Add domain` 。

<img width="1373" alt="スクリーンショット 2019-12-17 23.05.49.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22947/e0cd3a25-41c6-8c72-863e-bd50c8c371db.png">

そしたら「こういうDNSレコードを作ってね」というのが列挙されます。作っていきましょう。

# DNSレコード作成

今回はRoute53に作ることにしました。あらかじめ用意しておいた自前のドメインのhosted zoneに、DNSレコードを作っていきます。

使いたい用途に応じて取捨選択してください。メール送信だけなら、MXやCNAMEは作らなくて大丈夫です。

* TXT は Mailgun 経由でメール送信するのに必要です
* MX は Mailgun でメール受信する場合に必要です
    * 送信だけに使うなら、作らなくて大丈夫です。
* CNAME は Mailgun でメール開封追跡などするのに必要です
    * 開封追跡などやるつもりがないなら、作らなくて大丈夫です。

作例なので全部こさえました。DKIMは長いのでダブルクォートで囲むのが、無用なトラブルを避けるポイントですね。

<img width="428" alt="スクリーンショット 2019-12-17 23.29.16.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22947/60e69c22-1d7c-2186-ded8-6b477bbdf99a.png">

<img width="428" alt="スクリーンショット 2019-12-17 23.36.41.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22947/7f02f0d5-c0e8-13b5-d635-c7fd303bfb80.png">

<img width="425" alt="スクリーンショット 2019-12-17 23.37.47.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22947/785d6ba1-2cdf-737a-9905-25e0639cdfb2.png">

<img width="423" alt="スクリーンショット 2019-12-17 23.38.54.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22947/4da61299-f229-a198-2d1a-fdb6b4c6ac4e.png">

# DNSレコード確認

Route53に作成して放置してから `Verify DNS Settings` で確認できます。利用したい機能のぶんだけ、 `Enter this value` と `Current Value` が一致したら、利用開始できます。

<img width="1100" alt="スクリーンショット 2019-12-17 23.43.09.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22947/45ad461f-6178-7285-25f6-209bb89044f8.png">

設定完了するまでは、 Sending -> Overview から DNS設定を確認できます。

最低現として、メール送信できる状態になってからは、 Sending -> Domain settings -> DNS records で確認できます。

# 初めてのメール送信

Mailgunからのメール送信は、

* APIトークンを利用してAPIからの送信
* SMTPユーザー,パスワードを利用してSMTPからの送信

の2種類で送信できます。ここではAPIからの送信をやってみます。

## APIからの送信

メール送信などに利用するAPIトークンは https://app.mailgun.com/app/account/security/api_keys の `Private API Key` です。

てっとりばやくcURLで送ってみましょう。マニュアルはこちら。

* https://documentation.mailgun.com/en/latest/quickstart-sending.html

この感じで。Sandboxと異なり、任意のドメイン、メアドに送ることができます。つまり送ることができてしまうので、くれぐれも送って大丈夫なメアド宛に送りましょう。fromは自分のドメインであれば、任意のメアドから送ることができます。

```bash
$ export YOUR_API_KEY=xxxxxxxxxxxxxxxxxxx
$ curl -s --user "api:$YOUR_API_KEY" \
    https://api.mailgun.net/v3/mg.sasasin.net/messages \
    -F from="mailgun@sasasin.net" \
    -F to=hoge@example.com \
    -F subject='Hello' \
    -F text='Testing some Mailgun awesomeness!'
{
  "id": "<20191217155019.1.025538B5C9E2F167@mg.sasasin.net>",
  "message": "Queued. Thank you."
}
```


Mailgunの指示どおりにDNSレコードが設定できていて、APIトークンをミスっていなければ、メールボックスに届いているはずです。

# Mailgunでログを見る

Mailgunでは、成功失敗すべてのログを、Mailgunで確認することができます。あー、「すべて」ではない、条件付きです。

* API経由でもSMTP経由でも、とにかくMailgunに送りつけたのをMailgunが受けとった場合に限ります。
    * API経由なら、HTTP 200系となった場合は、Mailgun側にログが残ります。
    * SMTP経由なら、SMTP 250 OKとなった場合は、Mailgun側にログが残ります。

Sending -> Logs で見れます。

ログはこのように。いつ、誰名義で送って、誰宛に送って、宛先メールサーバーがどんなメッセージを返してきたか、がわかります。

<img width="1336" alt="スクリーンショット 2019-12-18 1.02.44.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22947/899d83a5-d8a2-1575-ea7d-59d2fa38c686.png">

ログはだいたい以下の4種類を見ればいいです。

* Accepted は、Mailgunが受けとってくれたログです
* Accepted の後、to のメアドにMailgunが送ろうとします。
* Delivered は、Mailgunからtoのメアドのメールサーバーに送信が成功したログです。
* Temporary Fail は、Mailgunからtoのメアドのメールサーバーに送信してみて、いくつかの理由で、一時的に失敗したログです。この場合は、Mailgunがリトライしてくれます。リトライ間隔を広げながら、一定回数で諦めます。
* Permanent Fail は、Mailgunからtoのメアドのメールサーバーに送信してみて、いくつかの理由で、送信失敗として完全に諦めたログです。Temporary Failでのリトライ回数上限に到達して諦めることもあれば、バウンスになって諦めることもあります。

漁るときは、だいたい以下を指定します。

* 問題となってる日時範囲
* 問題となってるメアド
* 問題となってるメアドのドメイン

ログの「...」で、いくつかのアクションが可能です。

* History で、そのメールの時系列ログを一括して見ることができます
* Quick View で、そのメールの本文を見ることができます
* Resend Message で、そのメールを再送することができます

ログの下向きの、、何て言うんだあれは、、、をクリックすると、Mailgunで持ってるログのJSON形式を見ることができます。あまり見ることはないですが。

# Mailgun でバウンスと苦情を管理する

Mailgunでは、メール送信して、先方のメールサーバーがバウンスだよって返してきたら、自動でサプレッションリストに入れて、以降はMailgunに送りつけても、Mailgunが先方に送らないようにしてくれます。Amazon SESなどのように、仕組みを自前で作る必要がありません。

Senging -> Suppressions で見れます。

たとえばですが、 `hogehoge@sasasin.net` という実在しないメアドに送ってみると、ログではAcceptedの後にFailedとなり、その理由は 5.1.1 云々 does not exist であったとわかります。

<img width="1386" alt="スクリーンショット 2019-12-18 1.22.51.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22947/07371f76-5a4a-2849-dc45-147a0d113225.png">

こうなるとサプレッションリストのBounceに登録されます。

<img width="1463" alt="スクリーンショット 2019-12-18 1.24.57.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22947/3b7784f1-71a8-5f5b-f464-3b262fe8922a.png">

再度、メールを送りつけてログを見ると、Acceptedになるものの、即座にFailedになります。理由は「Not delivering to previously bounced address」、サプレッションリストに存在しているので、Mailgunが外に出さないようにしています。

<img width="1400" alt="スクリーンショット 2019-12-18 1.26.10.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22947/b3e22e7a-814d-b8a4-4c92-938e77809e9b.png">

実運用として、サプレッションリストに入ったメアドの本人から問合せなどがあって、先方メールサーバーでの問題が解消したら、以降は送信したいはずです。その場合は、サプレッションリストで、検索ボックスにメアドを入れて、右端の `Delete` で、サプレッションリストから削除できます。先方メールサーバーで正しく問題が解消していれば、以降はメールが届くことでしょう。

<img width="1463" alt="スクリーンショット 2019-12-18 1.24.57.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22947/3b7784f1-71a8-5f5b-f464-3b262fe8922a.png">

ただちに確認したいのであれば、ログから Resend Message してみることで確認することができます。もし先方メールサーバーで問題が解消していない場合は、ふたたびサプレッションリストに入ってきます。

サプレッションリストに入った状態で Resend Message しても、ただちに「Not delivering to previously bounced address」となり送られません。

# カスタマーサポートにMailgunユーザーアカウントを発行する

いまのところ、あなたが利用しているMailgunユーザーは `Admin` 権限です。

あなたが運営しているサービスに、カスタマーサポートチームが存在するなら、メールが届かない云々のトラブルシュートを一部移譲することができます。

Mailgunでは `Support` という権限でユーザーを発行することができます。Mailgunでは何人ユーザーを発行しても追加課金は発生しません。

Settings -> Security & Users -> Invite New User で作成できます。

![スクリーンショット 2019-12-18 1.40.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22947/fc1dcf80-872b-6912-042a-a1a21635aa57.png)

権限ごとにできることは以下文書を。

* https://documentation.mailgun.com/en/latest/user_manual.html#managing-user-roles

# 固定IP

課金して、リクエストすると、固定IPをくれます。

Settings -> Dedicated IP -> Add Dedicated IP で、サポートケース作って「Dedicated IPちょうだい!!」って言ったら、わりとすぐにくれます。「すぐ」は長くとも24hくらいです。

IPのレピュテーションスコアは、クソではないけど、特に温まってもいないものが割り当てられます。いきなりすごい量を送ろうとすると死ぬはずなので、うまいことハンドリングしてください。ちなみに、それなり温めてから送ったはずなのに、outlook.comとその系列にガッツリはじかれて大変な目にあいました。

固定IPを使うなら、ユーザーにどのくらいoutlook.comの利用者がいるかを調査してからにすべきです。データベースからメアドのドメインだけ抽出してきて、雑ですが以下のようにnslookupでMXレコードを調べたらすぐわかります。変なドメインが混じってるとnslookupが固まりますので、うまくフィルタしてください。

```bash
#!/bin/bash
CSV=$1
cat $CSV \
| while read DOMAIN_NAME; do
	nslookup -type=MX -timeout=5 "$DOMAIN_NAME" \
	| grep exchanger | sort | head -n1 \
	| awk '{print "'$DOMAIN_NAME' " $0}'
done
```

# Mailgunのマニュアル類

以下に集約されてます。だいたいは User Manual と API References で解決できると思います。

* https://documentation.mailgun.com/en/latest/index.html

なんだか意味不明だったら、サポートに聞いたら答えてくれます。

# 各言語からメール送信するには

公式、野良、それぞれ各言語でライブラリがあります。

* https://documentation.mailgun.com/en/latest/libraries.html

もし専用ライブラリが存在してなくとも、だいたいSMTP送信するためのライブラリがある、、、あるよな、、はずなので、SMTP経由で送信したらよいです。

情報が探しにくいですが、それぞれ以下に出ています。

* APIトークン管理
    * Settings -> API Keys
* SMTPクレデンシャル管理
    * Sending -> Domain settings -> SMTP credentials

# まとめ

Mailgun はいいぞ。Amazon SESと比べると高いのですが、高いなりに理由がある。