Amazon SES+Lambdaでメール受信をトリガーにしてあれこれする(前編)

# メールの受信をトリガーにコードを動かす

…ことができます。そう、AWSならね。

[Amazon SES](https://aws.amazon.com/jp/ses/) はEメールの送受信を行うAWSのマネージドサービスです。
地味なサービスだなー誰が使うのかなーと思っていたんですが、こないだあるお店にネット経由で宅配を頼んだら、SESで注文メールが届きました。意外と使われているんですかね？

# 要約

* Amazon SES をセットアップしてメールを受信できるようにする
* SESでの受信をトリガーに、メールの生データをS3のバケットにPUTする
* そのPUTをトリガーに、Lambdaを実行して必要な情報を取り出す

SESのトリガーで、S3へのPUTだけでなくLambdaの実行もできるんですが、この先を踏まえて、あえて分けています。

# 必要な物

* [Route53](https://aws.amazon.com/jp/route53/) などのDNSサーバ

DNSサーバなら何でもいいんですが、Route53 だとSESのセットアップに必要な設定をほとんど自動でやってくれるのでお勧めです[^route53]。

[^route53]: 他のサービスとの相性もいいので、AWSの機能をフルに試すなら使った方がいいです。月々0.55USD(≒60円、2020年2月現在)ですし。ただクエリ数でも課金されるので、ときどきbillingダッシュボードを見た方がいいかもです。

# SESのセットアップ

SESは東京リージョンでは使えないので、ほかのリージョンを使います。ここでは「バージニア北部(`us-east-1`)」にしました。

## ドメインの検証

SESのコントロールパネルを開きます。
https://console.aws.amazon.com/ses/home

左側のメニューで Domains を選びます。

![ses-s3-domains.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223758/eca8423d-ce02-dc97-9938-fd9f871790d1.png)

上部の Verify a New Domain を押します。
入力欄が出てくるので、 **DNSサーバで自分が自由にレコードを操作できるFQDN** を入力します。

私は `keys.jp` というドメイン名を持っていて、Route53 で自由にレコードを操作できます。なので今回は以下のFQDNにしました。

![ses-s3-input-domain-name.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223758/b5854bc8-2cb6-3a14-ece2-46a888a819ed.png)

サブドメインをランダムな文字列にしているのは、**[SESでは受信メール数・サイズによって課金される](https://aws.amazon.com/jp/ses/pricing/)**ので、スパムなど余計なものを受け取らないようにしたいからです[^randomname]。

[^randomname]: アカウントの部分をランダムにしても同じ効果がありますが、その場合メールサーバまでのトラフィックが発生するので、DNSサーバのレコードを操作できるならこちらの方がいいでしょう。

[DKIM](https://www.nic.ad.jp/ja/basics/terms/dkim.html)の設定は、今回は受信のみなのでしません[^dkim]。

[^dkim]: もちろん、しても全然問題ないです。DKIMで使うTXTレコードも、Route53 なら自動で書いてくれますし。

最後に Verify This Domain を押します。

![ses-s3-verify-step.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223758/8b74aee7-938b-bc27-9223-ea3fddc99911.png)

Route53 を使っているなら Use Route53 を押します。（使っていない場合、画面にある2つのレコードを手動で追加します）

![ses-s3-use-route53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223758/8b54f47f-9e01-bd9b-dd49-9e3c3f089417.png)

ここで必ず **Email Receving Record** にチェックをいれます。でないとメールを受け取れません。（MXレコードが設定されません）
Hosted Zones の部分は、サブドメインの委任をしているときに確認、選択します。覚えがないひとは気にしないでOKです。

Create Record Sets を押します。

![ses-s3-veryfing.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223758/1394e8e7-27fa-2080-b8e2-744c929637f9.png)

問題なければ Verification Status が pending verification になっているはずです。

しばらく経つと、

![ses-s3-verified.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223758/686933c3-b7ee-bfa1-e2d2-64615c1d6c46.png)

こんな感じで verified になり、Enabled for も Yes になるはずです。

ドメインの設定はここまでです。

## SESからのデータを置くS3バケットの準備

（※S3の使い方はたくさん資料があるのでざっくり書きます）

受け取ったメールをPUTするバケットを用意します。リージョンはどこでもいいような気がするのですが、SESと同じ場所にした方がトラブルが起きにくそうな気がします。気がするだけですが。他の設定はそのままでOKです。

PUTする先は2箇所です:

* SESがPUTする、メールヘッダ付きでエンコードされた生データを置くところ
* Lambdaで処理したデータを置くところ

バケットは一緒でも違っていても問題ないです。ここではFQDNで1つのバケットを作ることにしました。

![set-s3-bucket-info.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223758/bcc26106-e5aa-728b-9dde-4866b731e29e.png)

あとはSESがバケットに生データをPUTできるように[バケットポリシーを設定します](https://docs.aws.amazon.com/ja_jp/ses/latest/DeveloperGuide/receiving-email-permissions.html)。

```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowSESPuts",
            "Effect": "Allow",
            "Principal": {
                "Service": "ses.amazonaws.com"
            },
            "Action": "s3:PutObject",
            "Resource": "arn:aws:s3:::BUCKET-NAME/*",
            "Condition": {
                "StringEquals": {
                    "aws:Referer": "AWSACCOUNTID"
                }
            }
        }
    ]
}
```

## 受信用アドレスの設定

メニューの左側にある Rule Sets を選びます。

![ses-s3-ruleset-list.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223758/c9c496d9-6919-d5f7-0f60-7831e8d12efb.png)

ルールセットについていろいろ書いてありますが、ここは最初から用意されている `default-rule-set` を使います。

View Active Rule Set を押します。

![ses-s3-ruleset.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223758/1169504b-4451-c46a-91e3-2c71b5e8e4fd.png)

Create Rule を押します。

![ses-s3-add-recipients.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223758/47ed8971-b745-475c-db78-b2d804535f38.png)

`Recipient` が、トリガーを引くためのアドレスです。さっきのFQDNで何か設定してください[^emptyrecipients]。

[^emptyrecipients]: 書いてあるとおり、なにも設定しないとそのドメイン宛てのメールすべてがトリガーになりますし、いろいろなパターンがあるので、必要ならドキュメントを見てみてください。

![ses-s3-recipient-added.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223758/b87d9c4a-2e51-92fa-1867-896c5c8e40c2.png)

FQDNは前もって設定したので `Verify` になっているはずです。
Next Step を押します。

## メール受信時の動作設定

メールを受け取ったときに行う動作を設定します。

![ses-s3-select-action.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223758/c216707d-3761-0b63-5821-fa6806f33feb.png)

S3を選び、さっき用意したバケットを設定します。

![ses-s3-action-selected.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223758/b73e5659-2165-f334-5477-e11f2a70928f.png)

生データと処理データを1つのバケットにいれるときはプレフィクスを付けます。ここでは `raw-data` にしました。

（※ちなみにここでLambdaも同時にトリガーを引くことができます）

Next Step を押します。

![set-s3-rule-details.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223758/fbac2274-5007-24a9-74bc-5727b7c12b95.png)

ルール名を付けるだけで、他のところはそのままで大丈夫です。
Next Step を押します。

つぎに確認画面が出て、問題なければ Create Rule を押します。

![ses-s3-rule-result.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223758/2ad9c976-6891-a69d-5cdd-6f97d12d9a64.png)

こんな感じで一覧に出ているはずです。
これで設定はすべて終わりです。

# テスト

## バケットの中身を確認する

![ses-s3-bucket-raw.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223758/629c1a4d-8e26-3657-6450-489e61daaa43.png)

バケットに `raw-data` ができていればOKです。
`AMAZON_SES_SETUP_NOTIFICATION` というオブジェクトがありますが、消しても大丈夫です。

## テストメールを送る

![ses-s3-send-testmail.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223758/9e15784d-0d59-397a-0e44-5f414d822272.png)

英数字以外だとエンコードされてテスト結果が分かりにくくなるので、まずは英数字だけでメールを書きます。

## メールが受信できていることを確認する

![ses-s3-bucket-after-received.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223758/40a521d0-555e-6821-10e2-65a0b4139a32.png)

時間がかかることがありますが、しばらくするとバケットにこんなオブジェクトができます。
中を見ると、さきほど送ったメールがヘッダとともに表示されるはずです。

```
:
: (先頭部分省略)
:
X-SES-DKIM-SIGNATURE: a=rsa-sha256; q=dns/txt; b=BW8HfmOz9lmLkndIH0QedyH+of6GJRNr+P0HthQdzqoLgywz+PYGbzBSaplWOtbPKEM6LPtwCxtq7+imZ5XGToDqZUZI6NemvjUf0MIv7/v0QlfmL7QOiVZuj52Yjxud8B8+UdPx7ToUeHEMrcW1ZYcnHTMD3mCfXyZn3salloQ=; c=relaxed/simple; s=6gbrjpgwjskckoa6a5zn6fwqkn67xbtw; d=amazonses.com; t=1582691942; v=1; bh=VVosbMywvKLFVhwuAQO2PounA7TnA2309xLqNuPoo9c=; h=From:To:Cc:Bcc:Subject:Date:Message-ID:MIME-Version:Content-Type:X-SES-RECEIPT;
Received: from mail-wr1-f54.google.com (mail-wr1-f54.google.com [209.85.221.54])
	(authenticated bits=0)
	by sendmail.example.com (8.15.2/8.15.2) with ESMTPSA id 01Q4cu6E003518
	(version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=FAIL)
	for <ses-s3-test@brcizzx4kk.keys.jp>; Wed, 26 Feb 2020 13:38:59 +0900 (JST)
	(envelope-from otegami@devel.keys.jp)
Received: by mail-wr1-f54.google.com with SMTP id u6so1315624wrt.0
        for <ses-s3-test@brcizzx4kk.keys.jp>; Tue, 25 Feb 2020 20:38:58 -0800 (PST)
X-Gm-Message-State: APjAAAV84Ls0YaytYszZs4ag7EoUndQseX3PxXjkVJ9PKQGdj3l3/VZL
	FF6MB2WzKh0jp4FegCvMPfXcratyro5kFPawZfY=
X-Google-Smtp-Source: APXvYqwH6qSjHTDgtIIu8j8rOh2gsIEoAAkKHLNQNkc04ndEzLjRHuQ6UQ3+MyRLciBiqwxoVLvIv83yv16WE9f8Io0=
X-Received: by 2002:adf:fdc2:: with SMTP id i2mr3100315wrs.166.1582691936426;
 Tue, 25 Feb 2020 20:38:56 -0800 (PST)
MIME-Version: 1.0
From: Kei Onimaru <otegami@devel.keys.jp>
Date: Wed, 26 Feb 2020 13:38:45 +0900
X-Gmail-Original-Message-ID: <CAJJjJ4inEYUHn_NkJiD=JB2n9R1Hy4PXXwA8ZJavTXn2deyG+A@mail.gmail.com>
Message-ID: <CAJJjJ4inEYUHn_NkJiD=JB2n9R1Hy4PXXwA8ZJavTXn2deyG+A@mail.gmail.com>
Subject: This is test mail
To: ses-s3-test@brcizzx4kk.keys.jp
Content-Type: text/plain; charset="UTF-8"

SES S3 Test

-- 
Kei Onimaru <otegami@devel.keys.jp>.
https://devel.keys.jp/
```

次はLambdaの設定です。

……が、ちょっと記事が長くなったのでいったんここまでで。