サーバーレスWebアプリにメールフォームを追加実装する 〜 バックエンド編 〜

# サーバーレスWebアプリにメールフォームを追加実装する 〜 バックエンド編 〜
## はじめに
[AWSを活用したサーバーレスWebアプリの制作](https://qiita.com/w2or3w/items/87b57dfdbcf218de91e2)で作ったWebアプリにメールフォームを追加実装します。
2部構成にしていて、先にフロントエンド編から見ると良いと思います。
[サーバーレスWebアプリにメールフォームを追加実装する 〜 フロントエンド編 〜](https://qiita.com/w2or3w/items/b05df2bf49cba13a542e)

## バックエンド
ベースとしたWebアプリはAppSyncを利用していますので、フロントエンドからメールを送るLambdaを呼び出す手段もAppSyncとします。

### Lambda関数の作成
Lambda関数の新規作成時、実行ロールの選択と作成で「Amazon SNS 発行ポリシー」を加えておきます。
![Screenshot 2020-03-29 at 08.53.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394775/93658795-05be-6f08-5f15-0cb1f938d07a.png)

### AppSyncにLambda呼び出しのIFを追加
すでに利用しているAppSyncにLambdaを呼び出すIFを追加します。
先日書いた以下の記事がさっそく役立ちますね。
[AppSyncでLambdaを呼び出す](https://qiita.com/w2or3w/items/54b5c84bed05d614629e)

上のLambdaをデータソースに加え、以下のようなIFをスキーマに追加し、リゾルバにアタッチします。

```graphql
input ProcessSendMailInput {
	name: String!
	email: String!
	message: String!
}
type ProcessSendMailResult @aws_cognito_user_pools {
	statusCode: Int!
	body: String
}
type Mutation {
	processSendMail(input: ProcessSendMailInput!): ProcessSendMailResult
		@aws_cognito_user_pools
 :
```

### AWS SNSの設定
AppSync経由で送られてきた内容をメール通知するためのSNSをセットアップしてゆきます。

#### トピックの作成
最低限、名前のみの入力で良さそうです。
![Screenshot 2020-03-29 at 10.05.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394775/03d0386f-9074-c38e-60fc-f73ca0304287.png)

#### サブスクリプションの作成
作成したトピックに対して、サブスクリプションの作成を行います。
プロトコルは「Eメール」、エンドポイントは「送信先のメールアドレス」とします。
![ink.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394775/748d5e74-0eec-f7f8-7eec-c41ed0480963.png)
サブスクリプションを作成すると、エンドポイントに指定したメールアドレスに確認メールが送られてきます。
![ink (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394775/53e83c78-d94d-0965-080a-c17c4be48c35.png)
メール本文にある「Confirm subscription」リンクを選択すると、サブスクリプションの認証が完了してステータスが「保留中の確認」から「確認済み」になります。

トピックの画面の右上にある「メッセージの発行」から、テストメールを送れるので、確認してみると良いと思います。
あと、トピック詳細にあるARNはあとでプログラムから利用します。

### Lambda関数の実装
AppSync経由で送られてきた内容をSNSで通知するPythonのコードです。

```lambda_function.py
import boto3
import json
import logging

logger = logging.getLogger()
logger.setLevel(logging.INFO)

sns = boto3.client("sns")
TOPIC_ARN = "arn:aws:sns:ap-northeast-1:888888888888:sample_sns_topic"
REQUEST_BODY_TEMPLATE = """
name : {0}
email : {1}
message : 
{2}
"""

def lambda_handler(event, context):
    try:
        logger.info(event)
        name = event["input"]["name"]
        email = event["input"]["email"]
        message = event["input"]["message"]
        
        requestBody = REQUEST_BODY_TEMPLATE.format(name, email, message)
        logger.info(requestBody)
        
        request = {
            "TopicArn": TOPIC_ARN,
            "Message": requestBody,
            "Subject": "mail from form by {0}".format(name)
        }
        response = sns.publish(**request)

        return {
            "statusCode": 200,
            "body": json.dumps("Email sent successfully.")
        }

    except Exception as e:
        logger.exception(e)
        return {
            "statusCode": 500,
            "body": json.dumps(e)
        }
```

## フロントエンドからAppSyncの呼び出し
[フロントエンド偏](https://qiita.com/w2or3w/items/b05df2bf49cba13a542e)へ記載してます。


## あとがき
メールフォーム、思ってたよりも簡単でした。これだけなら工数1.0Hくらいですね。
ただ、いたずら防止のための仕掛けは別途必要だと思います。

GoogleのreCAPTCHAっていうサービスを利用してみたいなと思ってるんですよね。
今度導入してみたらまた記事にしようと思います。