AWS(api gateway, lambda, SES, S3)を用いてお問い合わせフォーム付きウェブサイトを作成する

# AWS(api gateway, lambda, SES, S3)を用いてお問い合わせフォーム付きウェブサイトを作成する

こんな感じでシンプルに件名とメッセージだけ入れてメールで送信します。
![rapture_20211110233814.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356208/bfde2080-2972-f579-4fd0-a459887546f9.jpeg)
AWSのapi gateway, lambda, SES, S3を用いて、S3上にアップロードした静的ウェブサイト上からメールを送信したので、その手順を記録しておきます。

大まかに以下のような手順となります。

* SESへのメールアドレスへの登録
* lambdaを用いてメールの送信用の関数を作成(今回はPythonで行った)
* api gatewayへのlambda関数の登録
* apiを叩くためのwebサイトの作成
* 作成したwebサイトをS3上にアップロードし、公開する。

## SESへのメールアドレスの登録

まずSESに送受信するメールアドレスを登録します。

Amazon SESコンソールにアクセスして、Create identityを選択します。

![rapture_20211110231120.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356208/3036da3a-cb73-a113-8680-d67517d09b8b.jpeg)

Email addressを登録します。メールアドレスを入れて、Create identityを選びます。

![rapture_20211110231146.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356208/5f81e364-849c-339f-c23b-24c9d23c43da.jpeg)


認証メールが届くので、クリックして認証を行ってください。(ここで飛ぶリンクは変な場所にリダイレクトされますが、認証はされるので問題ありません。)



Verified identitiesから登録したメールアドレスを確認できます。

![rapture_20211110231408.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356208/b8e7c89d-92af-8767-6955-c5b5bc12488d.jpeg)

## lambdaを用いた処理作成

### 基本的な作成処理

AWS 
lambdaのコンソールにアクセスし、関数の作成をクリックします。

![rapture_20211110231755.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356208/012d595e-590c-df09-ed22-e8f9b5bc02e3.jpeg)


関数名、使う言語(今回はPython)を選択します。関数の作成をクリックします。

![rapture_20211110231938.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356208/96b6a432-c4d5-c6ba-9f33-e82f25fbf933.jpeg)
実行ロールは後から設定するので、ひとまず適当に設定しました。

このような画面が現れます。

![rapture_20211110232114.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356208/71ee1f29-5371-53ae-e6c8-d715ac7bd4a5.jpeg)




* コードのタブからコードを書きます。
  * Deployを押さないと変更が反映されないので注意してください。
  * Testボタンで動かすことができます。
* テストのタブでテストとして送信する値を設定できます。
  * 設定した値は関数lambda_handler()内でeventとして受け取って動かすことができます。

以下のようにコードを書き換えます。

```py
import boto3
import json

SRC_MAIL = "登録したメールアドレス-送信元"
DST_MAIL = "登録したメールアドレス-送信先"
REGION = "ap-northeast-1" #使用するリージョン

def send_email(source, to, subject, body):
    client = boto3.client('ses', region_name=REGION)

    response = client.send_email(
        Source=source,
        Destination={
            'ToAddresses': [
                to,
            ]
        },
        Message={
            'Subject': {
                'Data': subject,
            },
            'Body': {
                'Text': {
                    'Data': body,
                },
            }
        }
    )
    
    return response

def lambda_handler(event, context):
    r = send_email(SRC_MAIL, DST_MAIL, event["subject"], event["text"])
    return r
```

テストする際は以下のjsonを使用してください。

```json
{
  "text": "本文",
  "subject": "件名"
}
```

### IAMロールの設定

LambdaからSESにアクセスするために、IAMロールを割り当てます。

先ほどの画面から設定タブを開き、アクセス権限を見てみます。
![rapture_20211110232417.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356208/2d0bb046-d7cb-a8d1-10ee-a534e7705903.jpeg)

現在実行しているロールが見えるので、これをクリックします。

IAMコンソールが開きました。ここで割り当てられているロールをクリックしてみます。

![rapture_20211110232628.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356208/6229ba25-d6f0-38ed-5853-2d8a2a5c58a3.jpeg)

ポリシーの編集→JSONとクリックし、以下のように設定を書き換えます。

![rapture_20211110234828.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356208/0dc98cf3-ab68-9973-4151-439d19d4f12d.jpeg)


```

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "logs:CreateLogGroup",
        "logs:CreateLogStream",
        "logs:PutLogEvents"
      ],
      "Resource": "arn:aws:logs:*:*:*"
    }
    ,{
       "Effect": "Allow",
       "Action": ["ses:Send*"],
       "Resource":"*"
     }
  ]
}
```
この内容は[この記事](https://qiita.com/kskinaba/items/c692cadbe57121546413)をそのまま参考にしました。

## api gatewayへの関数の登録

api gatewayコンソールを開き、「APIを作成」を押します。

![rapture_20211110235512.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356208/d20b5d56-14ab-f2aa-3534-fd91d492674b.jpeg)

REST APIを選択します。
![rapture_20211111001311.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356208/19a87632-ce14-dfbf-2523-b89c7e7c4b28.jpeg)
名前等を設定し、作成を行います。
![rapture_20211111001330.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356208/f2362820-acff-a845-d21c-813d9fcd637c.jpeg)
このようなページが開くので、アクション→メソッドの作成を選択します。
![rapture_20211111001857.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356208/49694817-7342-25f3-1f56-087b33ae5674.jpeg)
作成したメソッドをPOSTに設定し、チェックをつけて決定します。

![スクリーンショット 2021-11-11 001457.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356208/35bf4db7-a4e1-4448-5302-ee5cbc5682c0.png)
そうすると設定画面が出るので、ここで先ほど作成した関数を設定します。
![rapture_20211111001551.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356208/836af600-dde2-131b-bba5-9f73bf9e2b96.jpeg)
決定すると、lambdaにアクセスする権限について聞かれるので許可します。

これで作成ができました。

このような画面が表示されるので、「テスト」を押してみます。

![rapture_20211111002510.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356208/69780c6d-0b53-e424-45b7-4c895d84a99b.jpeg)

リクエストとして先ほどと同様に以下を送信します。


```json
{
  "text": "本文",
  "subject": "件名"
}
```
メールが届けば成功です。

### CORSの有効化

apiを叩くため、CORSの有効化をしておく必要があります。
![rapture_20211111002720.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356208/e5dbc356-6bfc-f5d3-50d4-c8cca1a99b1d.jpeg)
以下のような画面が表示されます。そのまま決定してしまいましょう。
![rapture_20211111002821.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356208/efbe9b91-ff35-c29f-475e-6e904b780d4d.jpeg)

### デプロイ

作成したapiをデプロイしましょう。APIのデプロイを選択します。

![rapture_20211111003017.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356208/54e14881-250f-e8ed-3b9b-aff1bedc2292.jpeg)

ステージ名を適当に設定し、決定します。

そうするとステージのタブからデプロイしたapiを見ることができて、実際に使用するURIを取得することができます。

これでapi gatewayの設定は完了です。

## html、javascriptでページの作成
html,javascriptはそれぞれ以下のように書きました。

```html:index.html
<html>
<body>
<script src="https://apis.google.com/js/client.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.js"></script>  
<script type="text/javascript" src="test.js"></script>
<p>subject</p>
<input type="text" id="subject">
<p>text</p>
<input type="text" id="message">
<input type="button" value="submit" onclick="testRequest()">
</body>
</html>
```

```javascript:test.js
let testRequest = () =>{
    const str1 = $("#message").val();
    const str2 = $("#subject").val();
    $.ajax({
        type:"POST",
        url: "作成したURL",
        data:JSON.stringify({
            "text": str1,
            "subject": str2
        }),
        success: function(data){
            console.log(data);
        }
    });
}
```

## S3へのアップロード、公開

S3のコンソールにアクセスし、バケットの作成を行います。

![rapture_20211111004442.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356208/022670f3-e069-6233-9c62-c719b6bef7bc.jpeg)
公開するものなので、作成時に「パブリックアクセスをブロック」のチェックを外します。
![rapture_20211111004657.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356208/3dc573b9-7faf-5523-189a-50c1be9f92d2.jpeg)

作成したバケットにファイルをアップロードします。

![rapture_20211111004909.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356208/cff0f435-9f0f-bcfe-69e8-b5af1dad74ff.jpeg)

プロパティ→静的ウェブサイトホスティングから、静的ウェブサイトホスティングの設定をオンにします。

![rapture_20211111005017.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356208/eb1d1f98-9daa-9ee3-faa1-3dd864c7d382.jpeg)

さらにアクセス許可→バケットポリシーから、以下のバケットポリシーを設定します。

```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "PublicReadForGetBucketObjects",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::バケット名/*"
        }
    ]
}
```

もう一度静的ウェブサイトホスティングの設定を見ると、公開されるURLが表示されています。

これでアクセスしてみましょう。

![rapture_20211110233814.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356208/885af37a-8d63-d093-91f0-9a97caf45aae.jpeg)
目的のページが表示され、送信→メール受信まで確認できたら完了です。

こうして書くと長い手順になってしまいましたが、目的のページを作成することができました。

## 参考

* https://dev.classmethod.jp/articles/lambda-to-ses/
* https://qiita.com/ryonext/items/c4358c6da4c5b98f8a10!