API Gateway + Lambda + SES で安価な問い合わせフォームを構築しよう(後編)


前編は[コチラ](https://qiita.com/north-code/items/5bbc757df5751dbed8f1)

## SESの送信設定をしよう

まずはLamdaからメールの送信を行えるように、Amazon SESで送信の準備をします。
SESは、2018/02月現在、バージニア北部、オレゴン、アイルランドの3つのリージョンでしか提供されていないため、3つのうちいずれかを選択します。

![SES01.png](https://qiita-image-store.s3.amazonaws.com/0/171672/bf72e4bc-8ccf-65db-e4c3-e89c25f96d6a.png)

どこを選択しても構わないのですが、今回は**「米国東部(バージニア北部)」**を選択して手順を進めます。

次にSESのHome画面から、右側メニューにある**「Sending Statistics」**を選択します。

![SES02.png](https://qiita-image-store.s3.amazonaws.com/0/171672/1ccb42b3-7a8b-205d-a8c2-4fffb50a969a.png)

SESはデフォルトではSandbox状態となっており、事前に認証したメールアドレス、ドメインに対してしかメールを送信出来ないようになっています。
また、送信制限も掛かっており**200通/24Hかつ、1通/秒までしか送信することが出来ません。**

今回の問い合わせフォームという用途では特定のメールアドレスにしか送信しませんし、前提として月間500通程度ですので、このまま運用しても問題は出ないとは思います。
(宛先のメールアドレスを事前に認証しておけば)

ですが、念のため送信制限の解除を申請しておきましょう。

「Sending Statistics」を選択して表示された画面の中央あたりにある**「Request a Sending Limit Increase」**という青いボタンを押下してください。

![SES03.png](https://qiita-image-store.s3.amazonaws.com/0/171672/c67bacbc-8ef1-a984-48f9-82c848efe85d.png)

下図のページで、何に使うのか、どこのWebサイトで使うのか、申請理由は？といったことを入力するフォームがありますので、記入して**「送信」**ボタンを押しましょう。
大体ですが、遅くとも翌営業日には申請は承認されます。
申請する制限緩和「希望する一日あたりの送信クォータ」で良いと思います。
新しい制限値はとりあえず500くらいを指定しておきましょう。

![SES04.png](https://qiita-image-store.s3.amazonaws.com/0/171672/2da01b0d-4703-cb06-aa47-1a2b190e33cc.png)

これで送信先(To)に関しては制限なく使用出来るようになるのですが、**送信元(From)に設定するメールアドレスは、そのメールアドレスの持ち主であることを証明する必要があります。**
右側のメニューの**「Email Addresses」**を選択して、**「Verify a New Email Address」**ボタンを押してください。

![SES05.png](https://qiita-image-store.s3.amazonaws.com/0/171672/624a3b96-e9e5-6f36-b0d1-fec71e19ce93.png)

Eメールアドレスの入力欄がポップアップで表示されますので、SESから**送信するメールの送信元(From)に設定するメールアドレス**を入力して**「Verify This Email Address」**を押すと、入力したメールアドレス宛てに認証メールが送信されますので、その中にある検証用のURLをクリックすればOKです。

入力したメールアドレスのStatusが「verified」になっていることを確認しましょう。


![SES06.png](https://qiita-image-store.s3.amazonaws.com/0/171672/9ba6d640-b0e9-7410-8ac6-1b361f5716b4.png)

$$\style{align: center; font-size:1.2em; font-weight:bold;}{\text{↓}}$$

![SES07.png](https://qiita-image-store.s3.amazonaws.com/0/171672/5d6ba1ea-1daa-f7e9-6ded-6a0c3213d657.png)


## LambdaのFunctionを作ろう

次にメール送信を行うためのLambda Functionを作成します。
Lambdaのホーム画面を表示したら、**「関数の作成」**ボタンを押してください。

![Lambda01.png](https://qiita-image-store.s3.amazonaws.com/0/171672/8bbcfae7-a826-191b-e9f2-e1a7d12a02a4.png)

Lambda Function の名前や実行時のIAMRoleを指定します。
今回作成するFunctionはSESの送信権限を付与する必要がありますので、「ロール」の欄は**「カスタムロールの作成」**を選択してください。
名前は任意で構いません。ランタイムも自分の好きな言語で構いませんが、今回は「Node.js 6.10」を選択して手順を進めます。

![Lambda02.png](https://qiita-image-store.s3.amazonaws.com/0/171672/47934dc2-3933-b3a9-0422-f44176612a90.png)

「カスタムロールの作成」を選択すると、IAM Manegiment Consoleが表示され、Lambda FunctionにアタッチするRoleの作成画面に遷移します。

デフォルトでLambdaの実行に必要なログ出力用のポリシードキュメントが表示されていますので、任意のロール名を入力し**「編集」**リンクをクリックしてポリシードキュメントの編集を行います。

![IAM01.png](https://qiita-image-store.s3.amazonaws.com/0/171672/9ea929c1-00d7-f425-12fd-95df3c622278.png)

下記のSESからの送信を許可するステートメントを追加します。

```json:ポリシードキュメント
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "logs:CreateLogGroup",
        "logs:CreateLogStream",
        "logs:PutLogEvents"
      ],
      "Resource": "arn:aws:logs:*:*:*"
    }
    ,{
       "Effect": "Allow",
       "Action": ["ses:Send*"],
       "Resource":"*"
     }
  ]
}
```

**「許可」**ボタンを押すと、IAM Manegiment Console が終了し、Lambda Functionの作成画面に戻ります。
**「既存のロール」**という欄が増えているはずですので、**作成したSES送信用のRoleを選択して「関数の作成」ボタンを押しましょう。**

![Lambda03.png](https://qiita-image-store.s3.amazonaws.com/0/171672/3177ff53-aec4-47b3-2811-b1e19d8613dd.png)

関数コードを編集し、API Gatewayから受け取った内容をSESからメール送信するコードを記述して**「保存」**ボタンを押します。

![Lambda04.png](https://qiita-image-store.s3.amazonaws.com/0/171672/400ef2b2-7b53-8ddc-2665-27b5256747cb.png)

このLambda Functionは、API Gatewayから下記のようなJSONを受け取ることを前提としてコードを記述します。

```json:application/json
{
    "form": {
        "name":  "名前",
        "email": "Eメールアドレス",
        "body":  "問い合わせ本文"
    }
}
```

Lambda Functionの中身は下記のようにしています。

```JavaScript:index.js
'use strict'
const SDK = require('aws-sdk');

exports.handler = (event, context, callback) => {
    const ses = new SDK.SES({ region: 'us-east-1' });
    const email = {
        // From
        Source: "fromAdress@example.com",
        // To
        Destination: { ToAddresses: ["toAdress@example.com"] },
        Message: {
            // 件名
            Subject: { Data: "Webからのお問い合わせ" },
            // 本文
            Body: {
                Text: { Data: [
                    '[名前] : ' + event.form.name,
                    '[メールアドレス] : ' + event.form.email,
                    '[お問い合わせ] : ' + "\n" + event.form.body,
                ].join("\n")}
            },
        },
    };
    ses.sendEmail(email, callback);
};
```

コード内の **<font color="Red">fromAdress＠example.com</font>** の箇所は、SESで認証済みの送信元となるメールアドレスを記述してください。**<font color="Red">toAdress＠example.com</font>** の箇所は、送信先となる問い合わせフォームからのお問い合わせを受け取る担当者さんのメールアドレスを記述します。**(SESがSandboxの状態であれば、こちらのアドレスもSES認証済みである必要があります)**

この際、特に問題が無いのであれば基本設定やネットワークの欄はデフォルトのままで構いません。

![Lambda05.png](https://qiita-image-store.s3.amazonaws.com/0/171672/76871b6f-9dbb-483a-caa8-dbab0aec09f6.png)

また、Designer欄の**「トリガーの追加」**はAPI Gatewayを作成すると自動で追加されますので、この段階では特に何も指定する必要はありません。

## API GatewayをDeployしよう
最後にLamda Functionを実行するためのHTTPリクエストのエンドポイントとなるAPI Gatewayを作成します。
API Gatewayのホーム画面を表示したら、**「今すぐ始める」**ボタンを押してください。

![AG01.png](https://qiita-image-store.s3.amazonaws.com/0/171672/114cd632-b706-afe5-a941-fd2565f4bbd1.png)

任意のAPI名を入力して、**「APIの作成」**ボタンを押します。

![AG02.png](https://qiita-image-store.s3.amazonaws.com/0/171672/77a2b01d-c47f-b9f8-808b-0c384ca28cd7.png)

次にリソースの作成を行います。**「アクション」**からプルダウンを表示し、**「リソースの作成」**を選択します。

![AG03.png](https://qiita-image-store.s3.amazonaws.com/0/171672/75f4a0ca-b36b-b35d-208e-1132c195de02.png)

ここでは「send」というリソースを作成し、CORSを有効にしています。

![AG05.png](https://qiita-image-store.s3.amazonaws.com/0/171672/6381b6ad-06da-039d-d0af-7b5b8e883a61.png)

次に、作成したリソースに対してPOSTメソッドを追加します。
sendリソースを選択した状態で**「アクション」**からプルダウンを表示し、**「メソッドの作成」**を選択し、POSTを追加します。

追加したPOSTメソッドのセットアップでは、統合タイプには「Lambda関数」を指定し、作成したLambda FunctionのリージョンとFunction名を入力して、**「保存」**ボタンを押してください。

![AG06.png](https://qiita-image-store.s3.amazonaws.com/0/171672/a99e69f5-56a7-1a14-2be7-ea6a28e6e1f1.png)

POSTメソッドをセットアップしたら、メソッドの実行画面から**「統合リクエスト」**を選択します。

![AG07.png](https://qiita-image-store.s3.amazonaws.com/0/171672/92cb7bc2-55ef-2886-65b4-628fb129991a.png)

統合リクエストの編集画面を開いたら、**「本文マッピングテンプレート」**の追加を行います。この本文マッピングテンプレートにより、HTMLからPOSTされたJSONをLambda Functionに受け渡すJSONに変換します。

手順は**「マッピングテンプレートの追加」**から、**application/json** を追加してテンプレート内容を記述して**「保存」**ボタンを押します。

![AG08.png](https://qiita-image-store.s3.amazonaws.com/0/171672/2c66060e-1a7d-60db-4674-9dafcb910ea9.png)

テンプレート本文は下記のように記述しています。

```json:マッピングテンプレート
{
    "form": {
        "name":  "$util.escapeJavaScript($input.path('$.name'))",
        "email": "$util.escapeJavaScript($input.path('$.email'))",
        "body":  "$util.escapeJavaScript($input.path('$.body'))"
    }
}
```

これはHTMLから下記のようなJSONがリクエストBODYでPOSTされることを想定しています。

```json:HTTPRequestBody
{
  "name": "問い合わせ太郎",
  "email": "hogehoge@example.com",
  "body": "問い合わせ内容の本文"
}
```

POSTメソッドの統合リクエストの編集が完了したらAPIをデプロイします。

![AG10.png](https://qiita-image-store.s3.amazonaws.com/0/171672/f9b2ae39-c311-d432-1304-903232900c5c.png)

**「ステージ名」**は、任意の名称で構いませんが、ここでは「v1」と入力して手順を進めます。

![AG09.png](https://qiita-image-store.s3.amazonaws.com/0/171672/2dec0543-1c6c-3ee1-b36b-69ff296001a6.png)

デプロイが無事完了すると、APIのURLが払い出されます。

![AG11.png](https://qiita-image-store.s3.amazonaws.com/0/171672/23eab9eb-bb3f-fa28-411d-3fa157aa0408.png)

ここに表示されているURLに向けて、下記のようなJSONをPOSTするとLambda Functionが実行され、SESからメールが送信されます。

```json:HTTPRequestBody
{
  "name": "問い合わせ太郎",
  "email": "hogehoge@example.com",
  "body": "問い合わせ内容の本文"
}
```

これをS3にホスティングしたHTMLからJavaScriptで実行すると、問い合わせフォームの出来上がりですね。

## 最後に
いかがでしょうか？
前後編にわたり説明はかなり長かったと思いますが、手順的には簡単に問い合わせフォームを構築することが出来たのではないかと思います。
少なくとも私にはレンタルサーバー借りて、PHPで構築するよりはずっと簡単でした。(単にPHPが苦手なだけですが)

前編でお伝えした通り、これはどのサイトにも適用可能なものではありません。
それこそ月間数十万PV行くようなサイトや画像が盛りだくさんのサイトであれば**データ転送料で数千～数万円というケース**もあります。
もちろんレンタルサーバーの方が安く済むケースもありますので、「皆レンタルサーバー辞めて、AWSでサーバーレスしようぜ」という話ではないのですが、「小規模な静的サイトにちょろっとサーバースクリプトが欲しい」というケースでは、こういう方法もあるというのを知って頂ければ幸いです。

おつかれさまでした。