AWS SESでPythonからメール送信してみる

AWSのSES (Amazon Simple Email Service)を初めて使ってみました。

使い方は以下の公式ドキュメントがわかりやすかったです。

AWS SDK for Python (Boto) を使用して E メールを送信する - Amazon Simple Email Service

1. メールアドレス登録

メール送信時の差出人アドレスは事前にSESに登録して、メールアドレスの持ち主であることの確認をします。

SESのマネジメントコンソールから登録できます。

f:id:suzuki-navi:20210424212019p:plain

2. メール送信のPythonコード

import json

import boto3
from botocore.exceptions import ClientError

profile = "default"
region = "ap-northeast-1"

session = boto3.session.Session(profile_name = profile, region_name = region)
client = session.client("ses")

email_from = "Sample <sample@gmail.com>"
email_to = "sample_to@gmail.com"
charset = "UTF-8"

subject = "Amazon SES Test (SDK for Python)"

body_text = "Hello, SES!"

body_html = """<html>
<head></head>
<body>
  <p>Hello, <a href='https://aws.amazon.com/ses/'>Amazon SES</a>!</p>
</body>
</html>
"""

try:
    res = client.send_email(
        Source = email_from,
        Destination = {
            "ToAddresses": [
                email_to,
            ],
        },
        Message = {
            "Body": {
                "Html": {
                    "Charset": charset,
                    "Data": body_html,
                },
                "Text": {
                    "Charset": charset,
                    "Data": body_text,
                },
            },
            "Subject": {
                "Charset": charset,
                "Data": subject,
            },
        },
    )

except ClientError as e:
    print(e.response["Error"]["Message"])
else:
    print(json.dumps(res))

実行結果の例 (JSONをjqコマンドで整形してあります)

{
  "MessageId": "0106017903be5694-75c47c76-09fb-4da8-a430-1178fb4c1c04-000000",
  "ResponseMetadata": {
    "RequestId": "fd839fd9-914b-46bd-bb72-403c3da12446",
    "HTTPStatusCode": 200,
    "HTTPHeaders": {
      "date": "Sat, 24 Apr 2021 11:57:56 GMT",
      "content-type": "text/xml",
      "content-length": "326",
      "connection": "keep-alive",
      "x-amzn-requestid": "fd839fd9-914b-46bd-bb72-403c3da12446"
    },
    "RetryAttempts": 0
  }
}

3. 添付ファイル付きメール送信のPythonコード

ファイル添付も以下の公式ドキュメントがわかりやすかったです。

Amazon SES API を使用して raw E メールを送信する - Amazon Simple Email Service

Pythonemail.mime というパッケージを使うのですが、このパッケージに関する公式ドキュメントはこちら。

email.mime: Creating email and MIME objects from scratch — Python 3.8.9 documentation

boto3の send_email の代わりに send_raw_email というメソッドを使います。 email.mimeエンコードしたメール本文を send_raw_email でメール送信します。

import json

from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication

import boto3
from botocore.exceptions import ClientError

profile = "default"
region = "ap-northeast-1"

session = boto3.session.Session(profile_name = profile, region_name = region)
client = session.client("ses")

email_from = "Sample <sample@gmail.com>"
email_to = "sample_to@gmail.com"
charset = "UTF-8"

subject = "Amazon SES Test (SDK for Python)"

body_text = "Hello, SES!"

body_html = """<html>
<head></head>
<body>
  <p>Hello, <a href='https://aws.amazon.com/ses/'>Amazon SES</a>!</p>
</body>
</html>
"""

msg = MIMEMultipart('mixed')
msg['Subject'] = subject
msg['From'] = email_from
msg['To'] = email_to

msg_body = MIMEMultipart('alternative')
msg_body.attach(MIMEText(body_text.encode(charset), 'plain', charset))
msg_body.attach(MIMEText(body_html.encode(charset), 'html', charset))
msg.attach(msg_body)

# ローカルにある sample.txt をファイル添付
attachment = MIMEApplication(open("sample.txt", 'rb').read())
attachment.add_header('Content-Disposition', 'attachment', filename = "sample.txt")
msg.attach(attachment)

print(msg.as_string())

try:
    res = client.send_raw_email(
        Source = email_from,
        Destinations = [email_to],
        RawMessage = {
            'Data': msg.as_string(),
        },
    )

except ClientError as e:
    print(e.response["Error"]["Message"])
else:
    print(json.dumps(res))

以下は、 email.mimeエンコードした結果( msg.as_string() の部分の出力)の例です。

Content-Type: multipart/mixed; boundary="===============1385664818049781378=="
MIME-Version: 1.0
Subject: Amazon SES Test (SDK for Python)
From: Sample <sample@gmail.com>
To: sample_to@gmail.com

--===============1385664818049781378==
Content-Type: multipart/alternative; boundary="===============0301123813487367193=="
MIME-Version: 1.0

--===============0301123813487367193==
MIME-Version: 1.0
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: base64

SGVsbG8sIFNFUyE=

--===============0301123813487367193==
MIME-Version: 1.0
Content-Type: text/html; charset="utf-8"
Content-Transfer-Encoding: base64

PGh0bWw+CjxoZWFkPjwvaGVhZD4KPGJvZHk+CiAgPHA+SGVsbG8sIDxhIGhyZWY9J2h0dHBzOi8v
YXdzLmFtYXpvbi5jb20vc2VzLyc+QW1hem9uIFNFUzwvYT4hPC9wPgo8L2JvZHk+CjwvaHRtbD4K

--===============0301123813487367193==--

--===============1385664818049781378==
Content-Type: application/octet-stream
MIME-Version: 1.0
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="sample.txt"

SGVsbG8K

--===============1385664818049781378==--

追記

AWS SESではなく普通のSMTPサーバの場合を別記事に書きました。

suzuki-navi.hatenablog.com