LambdaからSESでメールを送信してみた

# 背景・目的
以前、SESについていくつか試してみました。

https://qiita.com/zumax/items/51efc16d469f77caf126

https://qiita.com/zumax/items/22a7bbc975a86afcb07a

今回は、LambdaとAmazon SESを活用して、サーバーレスからメール配信を構築する方法を試してみます。

# 概要
## 検証済みID
下記を基に整理します。

https://docs.aws.amazon.com/ja_jp/ses/latest/dg/verify-addresses-and-domains.html

> Amazon SES では､検証済みID は E メールの送受信に使用する ドメインまたは E メールアドレスです。Amazon SES を使用して E メールを送信する前に、「From」、「Source」、「Sender」、または「Return-Path」のアドレスとして使用する各 ID を作成し、検証する必要があります。Amazon SESでIDを検証することにより、IDを所有していることを確認し、不正使用を防止します。

- SESでは、検証済みIDは、メールの送受信に使用するドメイン、メールアドレス
- SESを使用してメール送信する前に下記をアドレスとして使用する各IDを作成して検証する必要がある
    - From
    - Source
    - Sender
    - Return-Path
- IDを検証することでIDを所有していることを確認し、不正使用を防止する

> アカウントがまだ Amazon SES サンドボックス内にある場合は、Amazon SES メールボックスシミュレーター から提供されたテストインボックスへ送信するメールを除いて、すべてのE メール予定送信先のアドレスも検証する必要があります。詳細については、「手動でメールボックスシミュレーターを使用する」を参照してください。

- サンドボックスにある場合は、すべてのメール予定送信先のアドレスも検証する必要がある
    - テストインボックスへ送信するメールを除く

# 実践
1. AWSにサインインします

## IAMを作成
### IAMロール
1. IAMに移動します
1. ナビゲーションペインで「ロール」をクリックします
1. 「ロールを作成」をクリックします
1. 下記を入力し、「次へ」をクリックします
    - 信頼されたエンティティタイプ：カスタム信頼ポリシー
1. カスタム信頼ポリシーを下記を入力し、次へをクリクします
    ```json
    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Effect": "Allow",
          "Principal": {
            "Service": "lambda.amazonaws.com"
          },
          "Action": "sts:AssumeRole"
        }
      ]
    }
    ```
1. 許可ポリシーを選択しないで、「次へ」をクリックします
1. 確認画面で、「ロールを作成」をクリックします

### IAMポリシーを作成
1. 上記で作成した、IAMロールを選択します
1. 「許可を追加」＞「インラインポリシー」をクリックします
1. JSONで下記を入力し「次へ」をクリックします
    ```json
    {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Effect": "Allow",
                "Action": [
                    "ses:SendEmail",
                    "ses:SendRawEmail"
                ],
                "Resource": "*"
            }
        ]
    }
    ```
1. ポリシー名を指定し「ポリシーの作成」をクリックします

## 送信先のメールを検証済みにする
### 登録
1. SESに移動します
1. IDの作成をクリックします
1. 下記を選択し、「IDの作成」をクリックします
    - IDタイプ：Eメールアドレス
    - Eメールアドレス：送信先に指定するメールアドレス
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/14afe38e-637b-45f9-9c33-e6bbe036f850.png)

1. IDステータスは、検証保留中になりました
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/c5657500-7b2a-4a49-96eb-9220862ed9d8.png)


### 検証
1. 登録したメールの受信ボックスを確認します
1. 「Amazon Web Services – Email Address Verification Request in region Asia Pacific (Tokyo)」という件名でメールが届いていますので、リンクをクリックします
1. 「メールアドレスの検証に成功しました」と表示されます

1. SESで確認すると検証済みになりました。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/e724cf00-a826-4410-aa22-fc378efad134.png)

## Lambdaの作成
1. Lambdaに移動します
1. 「関数を作成」をクリックします
1. 下記を入力し、「関数の作成」をクリックします
    - 関数名
    - ランタイム
    - 上記で作成したIAMロール
1. 下記のコードを入力し、「Deploy」をクリックします
    ```py
    import json
    import boto3
    from botocore.exceptions import ClientError
    
    def lambda_handler(event, context):
        
        # 検証済みの送信元のアドレス
        SENDER = "Sender Name <XXXXXXXXXXXXXXXX>"
    
        # 受信者のアドレス
        RECIPIENT = "XXXXXXXXXXXXXXXX"
        
        # 作成したConfig
        CONFIGURATION_SET = "ConfigSet"
    
        # SESを使用するリージョン
        AWS_REGION = "ap-northeast-1"
    
        # 件名
        SUBJECT = "Amazon SES Test (AWS Lambda)"
    
        # HTML Body
        BODY_HTML = """<html>
    <head></head>
    <body>
      <h1>Amazon SES Test (SDK for Python)</h1>
      <p>This email was sent with
        <a href='https://aws.amazon.com/ses/'>Amazon SES</a> using the
        <a href='https://aws.amazon.com/sdk-for-python/'> AWS SDK for Python (Boto)</a>.</p>
    </body>
    </html>
                """
    
        # 文字コード
        CHARSET = "UTF-8"
    
        client = boto3.client('ses',region_name=AWS_REGION)
    
        status_code = 200
    
        try:
            response = client.send_email(
                Destination={
                    'ToAddresses': [
                        RECIPIENT,
                    ],
                },
                Message={
                    'Body': {
                        'Html': {
                            'Charset': CHARSET,
                            'Data': BODY_HTML,
                        },
                    },
                    'Subject': {
                        'Charset': CHARSET,
                        'Data': SUBJECT,
                    },
                },
                Source=SENDER,
                ConfigurationSetName=CONFIGURATION_SET,
            )
        except ClientError as e:
            print(e.response['Error']['Message'])
    
        else:
            print("Email sent! Message ID:"),
            print(response['MessageId'])
    ```
## テスト
1. 「Test」ボタンをクリックします
1. 想定したメールが届きました
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/5740ac28-9587-467c-ab82-b66b18581c76.png)

# 考察
今回、SESのサンドボックス環境における制限事項・対処方法について確認し、LambdaからSESを通してメール送信まで確認できました。引き続き他の機能も確認していきます。

# 参考
https://docs.aws.amazon.com/ja_jp/ses/latest/dg/send-an-email-using-sdk-programmatically.html