AWS SESを使ってPythonからメール送信してみる


背景

AWS SESとは、メール配信サービスです。
Sendgridと似たサービスだと思われるため、使ってみます。

手順

1. AWSの設定

  1. Create identityを選択する

  1. DomainかEmailかを選択する。
    Domainだとレコードの変更が必要だと思われるので、一旦所持しているメールアドレスを選択してみる。

Emailを選択すると、メールアドレス入力画面が出てくるので、個人のメールアドレスを入力する

  1. Create identityを選択するとメールが受信する。
    赤いところが承認用URLですので、そこにアクセスして承認してください。

承認されます。

  1. SESの画面に移動すると承認が完了している事がわかります。

2.テストメール

  1. SESにアクセスして、承認されたメールアドレスをクリックする。

  1. Send test emailをクリックします。

  1. 適当に入力して、下部のSend test emailをクリックします
    このときにcustomを選択して、送信したい先のメールアドレスを入力しておきます。

  1. 指定したメールアドレスにテストメールが送信されたことが分かります

今回送ったのはGmailだったのですが、正常にメールが来ていることが確認できました。
※迷惑メールに入っている場合がるので注意してください。

3.pythonからメール送信する。

3.1 プリシンバルの作成

SES用の権限を作成する必要があります。
今回はメインのアカウントではなく、プリシンバル(いろいろな呼び方がサービスごとに違いますが)を作成してそれに権限を付与する形で進めたいと思います。

  1. IAMへ移動
    上部の検索窓にIAMと入力すると検索できるため、移動します。

  1. ユーザーに移動
    サイドバーのユーザーに移動します。

  2. ユーザー追加に移動
    右上のユーザーを追加をクリックします。

  3. ユーザ作成
    任意のユーザ名を入力し、アクセスキー-プログラムによるアクセスを選択します。

特に権限を付与せずに、進めます

タグも特につけません。

最終確認でユーザーの作成をクリックします。

とりあえず、権限なしのユーザが作成されます。

  1. sesに対するフルアクセス権限の付与

該当のユーザに対して、Permissions policiesAmazonSESFullAccessを付与しておきます。

3.3 実行

  1. 環境準備

AWS SDK for Python(boto3)を利用します。
python環境を準備し、下記のコマンドでインストールしてください。

pip install boto3
  1. 認証情報の設定

最初に前の章で作成したユーザのアクセスキーとシークレットキーを取得します。
ポータルでIAMの画面に移動して、サイドバーのユーザーをクリックします。

左側のリストに表示されている前回作成したses-userを選択します。
ユーザーの画面に移動後に画面中腹のタブ認証情報をクリックします。

アクセスキーの作成をクリックします。

アクセスキーIDシークレットアクセスキーをコピーし環境に設置します。

今回は~/.aws/credentialsに設置するやり方で進めたいと思います。

cd ~
mkdir .aws
nano ~/.aws/credentials
~/.aws/credentials
[default]
aws_access_key_id={{アクセスキーID}}
aws_secret_access_key={{シークレットアクセスキー}}

<参考:AWS SDK for python(Boto3)は認証情報をどこに置くか?>

https://zenn.dev/hashito/articles/81a02a803ed7c4
  1. ソースコード

下記のようなソースコードで実行します。
※{{}}内は任意の設定値に変更してください。

import boto3
from botocore.exceptions import ClientError

# Replace [email protected] with your "From" address.
# This address must be verified with Amazon SES.
SENDER = "{{sender mail}}"

# Replace [email protected] with a "To" address. If your account 
# is still in the sandbox, this address must be verified.
RECIPIENT = "{{recipent mail}}"

# Specify a configuration set. If you do not want to use a configuration
# set, comment the following variable, and the 
# ConfigurationSetName=CONFIGURATION_SET argument below.
#CONFIGURATION_SET = "pythonset"

# If necessary, replace us-west-2 with the AWS Region you're using for Amazon SES.
AWS_REGION = "{{REGION}}"

# The subject line for the email.
SUBJECT = "Amazon SES Test (SDK for Python)"

# The email body for recipients with non-HTML email clients.
BODY_TEXT = ("Amazon SES Test (Python)\r\n"
             "This email was sent with Amazon SES using the "
             "AWS SDK for Python (Boto)."
            )
            
# The HTML body of the email.
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>
            """            

# The character encoding for the email.
CHARSET = "UTF-8"

# Create a new SES resource and specify a region.
client = boto3.client('ses',region_name=AWS_REGION)

# Try to send the email.
try:
    #Provide the contents of the email.
    response = client.send_email(
        Destination={
            'ToAddresses': [
                RECIPIENT,
            ],
        },
        Message={
            'Body': {
                'Html': {
                    'Charset': CHARSET,
                    'Data': BODY_HTML,
                },
                'Text': {
                    'Charset': CHARSET,
                    'Data': BODY_TEXT,
                },
            },
            'Subject': {
                'Charset': CHARSET,
                'Data': SUBJECT,
            },
        },
        Source=SENDER
	#,
        # If you are not using a configuration set, comment or delete the
        # following line
        #ConfigurationSetName=CONFIGURATION_SET,
    )
# Display an error if something goes wrong.	
except ClientError as e:
    print(e.response['Error']['Message'])
else:
    print("Email sent! Message ID:"),
    print(response['MessageId'])

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

  1. 実行
    下記のコマンドで実行します。
python main.py
>Email sent! Message ID:
>0101017fe7de8172-f1731b47-1cfa-45f5-9c24-8357d85e82c9-000000

正常に終了するとMessage IDが出力されます。
また、メールボックスを見ると、実際にメールが配信されている事がわかります。

余談

configuration set?

メールを開封したとか、リンクをクリックしたを監視する設定のようです。
基本的に利用しなくても使えますが、Google Analyticsみたいなものなのでメーリングリストの利用率を上げたい場合などは利用を検討するべきだと思います。

迷惑メールになる

あまり詳しくないのですが、送信している実態と メール内のメールアドレスが異なると信頼度が減ります。
ですので、ドメインを登録していただいてそれベースで配信すれば問題は軽減されると思われます。

Sending authorization policies?

メールアドレス等に送信権限を与える設定のようです。

https://docs.aws.amazon.com/ja_jp/ses/latest/dg/sending-authorization-policies.html

この方が詳しく説明されていますので、参考にリンクを貼っておきます。

https://dev.classmethod.jp/articles/amazon-simple-email-service-sending-auth/