Lambda,APIGateway,SESを使ってメール送信機能を作ってみた

#はじめに
###Lambda
> AWS Lambda はサーバーをプロビジョニングしたり管理する必要なくコードを実行できるコンピューティングサービスです。 

公式ドキュメントはこちら[AWS Lambda](https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/welcome.html)
LambdaはS3バケット(バケットはS3内のディレクトリのようなもの)へのデータ変更などのイベントで勝手に動いてくれるもので、そのイベントが起きたときにLambdaが立ち上がり、中に書いたコードが呼び出されます。
リクエスト数に応じてサーバをスケーリングしてくれるので管理が必要ありません。
といってもリクエストや使うメモリ量によってお金がかかるのでお金の管理は公式ページから計算して行ってください。

###APIGateway
APIGatewayはAWSのマネージメントサービスで、APIの作成が行えるものです。
公式ドキュメントはこちら[Amazon API Gateway](https://aws.amazon.com/jp/api-gateway/)
APIGatewayはAPIの作成はもちろん、他のAWSのサービスとの連携もできます。
例えば先に説明したLambdaにも容易に接続出来ます。

###Amazon SES
>Amazon SES は、ユーザー自身の E メールアドレスとドメインを使用して E メールを送受信するための、簡単で費用効率の高い方法を提供する E メールプラットフォームです。

SESはメールの送信機能

公式ドキュメントはこちら[Amazon SES](https://docs.aws.amazon.com/ja_jp/ses/latest/DeveloperGuide/Welcome.html)


今回はこの3つのAWSソリューションを使ってメール送信機能を作成しました。

#実装方法
###手順1:API GatewayでAPIを作成する
APIGatewayとLambdaの作成順番はどちらからでも良いですが、まずはAPIをAPI Gatewayで作成していきます。
AWSコンソールからAPIの作成を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314384/23fed859-80a1-ac47-e1e5-0e4181b02ad6.png)
今回はリアルタイム性は求めていないのでプロトコルはRESTを選択します。
APIの作成方法は完全に新規で作成しようと思うので新しいAPIを選
択しました。
各作成方法はこちらもドキュメントを参考にして下さい。
後は名前と説明、エンドポイントタイプを選択してAPIのがわは完成です。

次にリソースとメソッドを定義していきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314384/2a7a7434-bf05-3f87-e1c4-6391575f641d.png)
sendmailというリソースを作成し、メソッドの定義を行います。
今回はLambdaに接続するのでLambda関数を選択し、Lambdaプロキシ統合の使用をチェックします。
Lambda関数の欄には次に作成するLambdaの関数名を入力します。
保存を押して作成完了です。

###手順2:Lambdaの関数を作成する
次にAPI GatewayからコールされるLambdaの関数を作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314384/f0d6d093-273d-4737-571c-8680648f09a4.png)
AWSコンソールからAWS Lambdaを選択し、この画面に移動してきます。
右上の<関数の作成>ボタンを押すと下のような画面になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314384/55e7854a-852c-1a72-fdd3-4c0faac73fa8.png)
ここでまず関数の雛形を作成します。

オプションの選択として、一から作成、設計図の使用、Serverless Application Repositoryの参照がありますが、今回は一から作成を選択するので残りの2つの説明を軽くしておきます。

設計図の使用：これは色々な機能(例：Hello Worldを表示する、S3にイベントが起きたら感知する)を最低限動くテンプレートとして使用出来るものとなっています。様々なテンプレートがあるので、使えそうなものがあれば試してみてください。

Serverless Application Repositoryの参照:こちらは既に用意してある自分で作成したプログラムを使用する場合に使います。やることが結構多いのでこちらは割愛させていただきます。

話を戻して、今回は一から作成を使うのでボタンを選択し、関数名を記載、Lambdaで使用したい言語をランタイム欄から選択します。
自分はPythonを選択しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314384/6a5eeada-3c60-2ec6-eaf3-deb432c17acf.png)

アクセス権限欄の実行ロールに関しては、AWSリソースへのアクセス権限を別途自分で作成し、選択します。
今回はLambdaからSESにアクセスを行うためSESへのアクセス権限をつけたロールを作成し、選択しました。
ロールの作成方法についてはこちらを参考にしてください [IAM ロールの作成]
(https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/id_roles_create.html)

下記が実際のpythonのコードです。

```python:lambda_function.py
#!/usr/bin/env python
# coding:utf-8
import boto3
import textwrap
import json
import re
from dateutil.parser import parse

#email config
region = 'us-east-1'
sendFrom = 'xxxx@xxxx.com'
sendTo = 'xxxx@xxxx.com'
subject = 'テストメールです'


def send_email(sendFrom, sendTo, subject, mailBody):
    client = boto3.client('ses', region_name=region)

    response = client.send_email(
        Source=sendFrom,
        Destination={
            'ToAddresses': [
                sendTo,
            ]
        },
        Message={
            'Subject': {
                'Data': subject,
            },
            'Body': {
                'Text': {
                    'Data': mailBody,
                },
            }
        }
    )

    return response

def make_body(information):
    mailBody = textwrap.dedent('''
    こんにちは、
    テスト用にメールを送信しています。
    改行を入れなくてもこれでフォーマットして送信できます。
    ''').format().strip()
    return mailBody
    
def make_response(statusCode, message):
   return {
        'headers': {
            'Access-Control-Allow-Origin' : '*',
            'Access-Control-Allow-Headers ': '*'
        },
        'body': '{"message": "' + message + '"}',
        'statusCode': statusCode,
    } 

def lambda_handler(event, context):
    if 'x-requested-with' not in event['headers']:
        return make_response(500, 'invalid_header')
    
    if event['headers']['x-requested-with'] != 'XMLHttpRequest':
        return make_response(500, 'invalid_header_value')
    
    mailBody = make_body(json.loads(event['body']))
    response = send_email(sendFrom, sendTo, subject, mailBody)
    return make_response(200, 'ok')
```
boto3というのはAWSがpython用に提供しているSDKで、AWSサービスを利用する際に使用出来るライブラリになっています。[Boto3](https://aws.amazon.com/jp/sdk-for-python/)

これでLambdaの設定も完了です。
ちなみにLambdaのテスト欄でテストを作成すると、API Gatewayからのリクエストをモックにしてテストすることが可能です。

###手順3:SESの設定を行う
※SESに関しては東京リージョンがないため他のリージョンで行います。

今回はテスト用に作成しただけなので、デフォルトのSandboxのままで行いました。
Sandboxでは指定したアドレスにしかメールが送れないため、まずメール送信の認証を行う必要があります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314384/b7c47090-1b1c-11de-a9bf-fbdabc217718.png)
Verify a New Email Addressから疎通させたいメールアドレスを記載すると、そのメールアドレスに認証メールが届きます。認証する前はステータスがpending verificationになっています。
届いたメールの中のリンクを押すとverifiedとなり、メールが送信できるようになります。

Sandboxの制限として、
・事前に登録したメルアド以外には送信できない
・1日当たり200通までしか送信できない
・1秒当たり1通までしか送信できない
があります。
別途、送信制限の解除を申し込むと上記の制限がなくなり商用として使用することができます。
[SES 制限解除](https://docs.aws.amazon.com/ja_jp/ses/latest/DeveloperGuide/submit-extended-access-request.html)


###手順4:実際にAPIをコールしてみる
各設定が完了したら実際にAPIをコールしてみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314384/19b54495-5472-c189-f275-c5cd700c093e.png)
無事メールが届きました。

##まとめ
以上4ステップでAWSサービスだけを利用してメールの送信機能が作れます。
マネージドサービスを使うことでもろもろ自分で準備しなくてよいのは大変楽でした。
参考になれば幸いです。
後はAPIにパラメータを渡したり、メールの本文を変えたり、Lambda側でバリデーションをしたりして好きに合わせて作ってみてください！

参考ドキュメント:[AWSホームページ](https://aws.amazon.com/jp/)