読者です 読者をやめる 読者になる 読者になる

やーまんぶろぐ

気が向いた時にだけ書くブログ

SendGridのメール受信方法 AWS EC2 Nginx編

AWS EC2 Nginx SendGrid

SendGridを使って受信したメールをトリガーにアクションを起こすようなアプリケーションの実現方法を検討しようと思っています。

前回の記事でも書きましたが、SendGridを使ってメール受信するにはInbound Parse Webhook を使う必要があるので、まずはそこらへんを使ってみることにしました。
yamano3201.hatenablog.jp

今回は、AWS環境のEC2上で動かしているNginxがメールを受信するまでのメモを書いていきます。

Parse Webookのデモ用ドメイン(bymail.in)を使ってメールを受信

下のリンクを少し参考にしました。
cloudautomator.com

bymail.inというデモ用のドメインがあるようなので、まずはそちらを使いました。
f:id:yamano3201:20160422000213p:plain

デモ用のドメインにメールを送ると、SendGrid経由でメールをHTTPリクエストとしてアプリが動く予定のEC2が受信するという流れになります。

AWS側の設定】Route53にMXを登録

Hosted Zone にデモ用のドメインであるbymail.inを作成します。
f:id:yamano3201:20160422000530p:plain

続いてテスト用のドメインにメールすると、SendGridの用意しているメールサーバに飛ぶようにMX Recordを作成します。
(当たり前だけど)A RecordはSendGrid側で用意しているので設定は不要。

↓登録した設定になります。(SendGridアカウントである XXXXXX@kke.com のXXXXXXの部分を使用します)

XXXXXX.bymail.in MX 100 mx.sendgrid.net.

f:id:yamano3201:20160422000913p:plain

【SendGrid側の設定】POST先のURLを指定

HOSTNAMEにはさきほどのXXXXXX.bymail.in を指定し、URLにはPOST先のURLを指定します。
(この段階では、http://EC2のパブリックIP/mail としました)

f:id:yamano3201:20160422001313p:plain

AWS側の設定】SecurityGroupの設定

SendGridのために特定のポートをフルオープンするわけにはいかないので、SecurityGroupを設定しておくことにしました。最初はSendGrid側の叩いてくるIPがわからなくて少し悩みました。
※ mx.sendgrid.netはmailを受け付けるところであって、POSTしてくるところではないので注意

dig mx.sendgrid.net +short
167.89.125.4

仕方がないので、一瞬だけ80番ポートをフルオープン(0.0.0.0/0)にして、メールを5通ほど送ってみました。

POST先として指定した http://EC2のパブリックIP/mail が動いているEC2サーバにログインしてNginxのログからIPを確認します。

sudo tailf /var/log/nginx/access.log

167.89.125.238 - - [21/Apr/2016:04:05:50 +0000] "POST /mail HTTP/1.1" 404 168 "-" "SendGrid 1.0" "-"
167.89.125.227 - - [21/Apr/2016:04:06:40 +0000] "POST /mail HTTP/1.1" 404 168 "-" "SendGrid 1.0" "-"
167.89.125.251 - - [21/Apr/2016:04:06:53 +0000] "POST /mail HTTP/1.1" 404 168 "-" "SendGrid 1.0" "-"
167.89.125.223 - - [21/Apr/2016:04:08:27 +0000] "POST /mail HTTP/1.1" 404 168 "-" "SendGrid 1.0" "-"
167.89.125.250 - - [21/Apr/2016:04:08:44 +0000] "POST /mail HTTP/1.1" 404 168 "-" "SendGrid 1.0" "-"

この結果からSendGrid側のPOSTしてくるホスト群を 167.89.125.0/24と推測しました。
※このIPは推測であり変更されてもおかしくない値です。この方法は本番では使えないので注意しましょう。

【EC2のNginxの設定】セキュリティについて考える

AWS側のSecurityGroupではドメイン単位で制限することはできないので、Nginx側でできないか調べてみました。

IPからいくつか名前を逆引きすると、*.outbound-mail.sendgrid.net.であることがわかります。

dig -x 167.89.125.238 +short
o16789125x238.outbound-mail.sendgrid.net.

dig o16789125x238.outbound-mail.sendgrid.net. +short
167.89.125.238

このドメインのみを許可することがNginxでできればSecurity Groupに頼る必要はなくなりそうですね。

※ ngx_http_referer_moduleの書き方メモ

location /mail {
    valid_referers server_names *.outbound-mail.sendgrid.net;
    if ($invalid_referer) { return 403; }
}
  • 暫定策
    • 167.89.125.0/24でSecurity Groupでアクセス制限。変わる可能性はあるので本番では使えないのはそのまま。
    • User-Agentでアクセス制限。ヘッダの中身は偽れるのでセキュリティはそこまで高くない

※User-Agentのアクセス制限の書き方メモ

location /mail {
    if ($http_user_agent = "SendGrid 1.0") { return 200; }
    return 403;
}

独自ドメインでメール受信

ここまでテスト用のドメインで進めてきましたが、独自ドメインに切り替えてみましょう。

ドメインを持ってなければ、まずはドメインを購入しましょう。
yamano3201.hatenablog.jp

購入したドメインをRoute 53で登録して、さきほどと同じようにmx.sendgrid.net. に飛ぶように設定します。
ここでは mail.yamano.購入したドメイン MX 100 mx.sendgrid.net. としました。

f:id:yamano3201:20160422004011p:plain

おまけ

メールじゃなくHTTPアクセスのほうのホストは、yamano.購入したドメイン としています。
さきほどEC2のパブリックIPとしていたところにはEIPをつけてRoute 53で紐付けておきました。

f:id:yamano3201:20160422004421p:plain

Valueの値はEIPの値になります。

最後に

セキュリティのところは課題が残ってしまいました。reverse DNSが遅くなければ良いのですが。。
後はHTTPじゃなくてHTTPSで受けたほうが良いでしょうね。

話題のLet’s Encryptあたりを触ってみるのも面白いかもしれません。
postd.cc

気が向いたら、また書きます。