Sendgridでセカンダリメールサーバーを作る 

# 概要

Sendgridの機能で[Inbound Parse Webhook](https://sendgrid.com/docs/for-developers/parsing-email/setting-up-the-inbound-parse-webhook/)というものがあります

これは受信したメールの内容を指定したURLにPOSTしてくれる機能です
sendgridはHTTPステータスコード200 OKまで再送し続けてくれるのでセカンダリのメールサーバーに使えそうです

ということでこの機能を使ってセカンダリのメールサーバを作ってみます
構成はこんな感じ
Inbound Parse Webhook でPOSTされる値を [Cloud functions](https://cloud.google.com/functions?hl=ja) で受け取ってプライマリのメールサーバに届けます

![Inbound parse.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106549/01a60108-e352-3d8a-3714-40fb2bcbd224.png)

# 構築

まず、以下のようなスクリプトを書いて、cloud functions関数を作成します
今回はすべての同じドメインの全てのアドレスを受け取り、ヘッダを含むメッセージをそのまま流しています
宛先のチェック、SPAMチェック等をする場合はここでチェックして破棄すると良いと思います
転送先のアドレスは25番ポート以外にしてください( [GCE同様25番はブロックされているため](https://cloud.google.com/compute/docs/tutorials/sending-mail?hl=ja) ）
また、SMTP AUTH, STARTTLS等の送信設定に関してはプライマリのメールサーバに合わせて適宜変更します

サンプルコードはこちら
https://github.com/yaasita/inbound_parse_receive

以下のようにdeployします

```bash
git clone https://github.com/yaasita/inbound_parse_receive.git
cd inbound_parse_receive
vim index.js # 適宜修正

# ローカルでテスト
npm run start
# multipart/form-dataで送る あと、 Content-Type: application/octet-stream をつけない
curl -X POST -F "email=<test.eml" http://localhost:8080/

# deploy
gcloud functions deploy webhook-receive --gen2 --runtime=nodejs16 \
    --region=asia-northeast1 --entry-point=handler \
    --trigger-http --allow-unauthenticated
```

次に、sendgridの管理画面から、`Settings` -> `Inbound Parse`と進み、ドメインを追加します
URLに先程作ったcloud functions関数のURLを指定します
今回はメッセージをそのまま転送するため、`POST the raw, full MIME message`にもチェックを入れておきます
ちなみに、Check incoming emails for spamにチェックすると、Spam reportとSpam Scoreもパラメータに付与してくれます(詳細は後述)
![sg-settings.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106549/7f9fb762-31bd-4edf-a29b-2c03d6e8f3e2.png)

あとはDNSサーバーのMXレコードを編集すればOKです

設定例

```
example.net.             60      IN      MX      10 example.net.
example.net.             60      IN      MX      20 mx.sendgrid.net.
```

# その他細かいこと

以下は公式情報ではない部分があります
時期や、アカウントによって変わる可能性があります
あくまで一例という事でお願いします
※2020年4月に調べた情報です

## メッセージサイズの上限は？

20MBらしいです
> The total message size limit, including the message itself and any number of attachments, is 20MB.

https://sendgrid.com/docs/for-developers/parsing-email/inbound-email/

ただ、試してみたところ、142MB程度まで、送ることができました・・・何でですかね？
143MBあたりから以下のエラーが出るようになりました

    '552 5.3.4 Error: message file too big'

今回の場合はCloud Functionsの[HTTPリクエストサイズ上限が10MB](https://cloud.google.com/functions/quotas?hl=ja)なのでそちらが先に制限に達すると思います

## POST the raw, full MIME messageにチェックしないと？

`text`というパラメータで本文だけがPOSTされますが、このチェックを付けると、`email`となって、ヘッダ+本文がまとめて取得できます
今回はそのまま転送するのでチェックしています

## Spam reportってどんな感じ？

先ほどのsendgrid設定画面で`Check incoming emails for spam`にチェックすると、Spam reportとSpam ScoreもPOSTするパラメータに付与してくれます


内容はSpamAssassinのレポートみたいです

https://sendgrid.com/docs/for-developers/parsing-email/setting-up-the-inbound-parse-webhook/#-Default-Parameters

spam report

    Spam detection software, running on the system "xxx.sendgrid.net", has
    identified this incoming email as possible spam.  The original message
    has been attached to this so you can view it (if it isn't spam) or label
    similar future email.  If you have any questions, see
    @@CONTACT_ADDRESS@@ for details.

    Content preview:  xxxxxxxxxxxxxxxxxx [...]-

    Content analysis details:   (0.0 points, 5.0 required)

     pts rule name              description
    ---- ---------------------- --------------------------------------------------
     0.0 FREEMAIL_FROM          Sender email is freemail (xxxxxx[at]example.com)
     0.0 TVD_SPACE_RATIO        TVD_SPACE_RATIO
     0.0 T_TO_NO_BRKTS_FREEMAIL T_TO_NO_BRKTS_FREEMAIL

spam_score

    0.012


## 再送の頻度は？

試してみると以下のようにリトライしてくれました。
https://gist.github.com/yaasita/16ab255370363f6620c10d47e090b4b8

6回目までは5分後にリトライ, 7回目は10分後, 8回目は15分後, 9回目は30分後, 10回目は1時間後, 11回目以降は3時間後みたいに長くなっていくみたいです
postfixのように、すぐ再送間隔が倍になることはないみたいですが、時間が経つと再送間隔が長くなっていくのは同じみたいです
再送処理は3日経つまで繰り返してくれます

## DMARCに対応してる？

対応してないみたいです
ポリシーがp=rejectでも、指定したURLにPOSTされました
DMARCのレポートも送信されませんでした

## bounceはする？

bounceはしないです
3日間の再送処理の後は静かにメッセージが消えるだけでした
postfixみたいにbounce_queue_lifetimeを越えたら送信元にエラーメッセージが届くわけではなさそう

`Mail Settings`の`Forward Bounce Messages`も関係なかったです

## 再送処理中に送信先URLは変更できる？

[APIを使用](https://sendgrid.kke.co.jp/docs/API_Reference/Web_API_v3/Webhooks/parse.html)して変更できました


コマンド例

    curl -s \
        -X "PATCH" "https://api.sendgrid.com/v3/user/webhooks/parse/settings/example.net" \
        -H "Authorization: Bearer xxxxxxxxxxxxxxxx" \
        -H "Content-Type: application/json" \
        -d '{ "url": "https://example.net/newurl", "spam_check": false, "send_raw": true }'

タイムラグはありますが新しいURLに向き先が変わります。
POST受信側で対応が難しい場合にURLを変更して対応することも可能です
(今回の例だと、cloud functions側の制限を超える20MBのメールを受信したい場合など)

## zapierでも出来る？

今回は、セカンダリのメールサーバーとして使いたかったので、cloud functionsを使いましたが本文を見るだけならzapierの方が確認かと思います
(WebhooksはPREMIUMアプリなのでなのでStarterプラン以上が必要です)
ただし、DKIM署名や、Fromアドレスは書き換わってしまいます

[SendGridで受信したメールの内容をメールクライアントで確認する](https://sendgrid.kke.co.jp/blog/?p=9806)