JavaScriptを有効にしてください

【AWS, SES】python(boto3)を利用してメールを送信する

 ·  ☕ 4 分で読めます · 👀... ページ閲覧数

背景

処理の結果に応じて自動的にメールを送信する機能を作りたかった。
最終的にファイルを添付したメールを送れるようにしたい。
試してみる。

試してみる

[step1] aws cliを利用したメールの送信方法

AWSCLIを利用して送るとどうなるのか試してみた。
リージョンはオレゴンで利用していたのでオレゴンのIDを指定。

1
2
3
4
5
6
$ aws --region us-west-2 --profile=<プロファイル名> ses send-email --to send_to@example.com --from send_from@example.com --subject sample --text "`echo -e hogehoge`"

# 送信完了するとMessageIdが表示される
# {
#     "MessageId": "01010175efc9f343-a80ee339-a377-4228-bbfb-83c3d2e4ad40-000000"
# }

使っていたgmailを宛先にして実施し、送信後メールボックスを確認すると無事にメールが届いていた!
次はファイルを添付して送信してみたいところだが、aws cliでファイルを添付する方法がすぐに検索できなかった。。。

そのため、次はpython(boto3)を利用してメールを送れるように試してみる。

[step2] python(boto3)を利用してメールを送信する

ファイルの添付などせず、そのまま送信する。
以下のサイトが参考になった。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import boto3

client = boto3.client(
    'ses',
    aws_access_key_id='YourAccessKey',     # アクセスキー
    aws_secret_access_key='YourSecretKey', # シークレットキー
    region_name = 'us-west-2'              # リージョン(今回はオレゴン)
)

# メール送信
client.send_email(
    Source = 'from@example.com',              # 送信元メールアドレス
    Destination = {
        'ToAddresses': ['to@example.com']     # 宛先メールアドレス
    },
    Message = {
        'Subject': {
            'Data': 'title',
            'Charset': 'UTF-8'
        },
        'Body': {
            'Text': {
                'Data': 'hello',
                'Charset': 'UTF-8'
            }
        }
    }
)

[step3] ファイルを添付してメールを送信する(python, boto3)

公式をみてみると、ファイルを添付してメールを送信する場合、send_emailではなくsend_raw_emailを利用するらしい。
send_raw_emailはsend_emailと引数が異なるため少し詰まった。
公式にある例を参考にしてなんとかメールを送信することはできた。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
import boto3


client = boto3.client(
    'ses',
    aws_access_key_id='YourAccessKey',
    aws_secret_access_key='YourSecretKey',
    region_name = 'us-west-2'
)

# メール送信
client.send_raw_email(
    Source = 'from@example.com',   # 送信元メールアドレス
    Destinations=[                 # 送信先メールアドレス
        "to_1@example.com",
        "to_2@example.com"
    ],
    RawMessage={
        'Data': 'Subject: Test email (contains an attachment)\nMIME-Version: 1.0\nContent-type: Multipart/Mixed; boundary="NextPart"\n\n--NextPart\nContent-Type: text/plain\n\nThis is the message body.\n\n--NextPart\nContent-Type: text/plain;\nContent-Disposition: attachment; filename="attachment.txt"\n\nThis is the text in the attachment.\n\n--NextPart--',
    },
)

受信されたメールをみてみると、

This is the text in the attachment.

という内容ファイル(attachment.tx)が添付されたメールが届いていた。

また、Destinationsに複数設定すると複数のメールアドレスがToに設定されるものかと思ったが、そうではなく、それぞれ別々のメールとして送信されているようだった。

一応メールを送信することはできたものの、あまりにも不格好なのでもう少しやってみる。
To, Cc, Bccや添付ファイルの中身、内容などを全てRawMessageに含めるのではなく、それぞれ分けて設定できるようにしたい。
(最悪最後にRawMessageとして結合するしかないのかもだが。。。)

このあたりを参考に。。

作ったサンプルソースがこちら。
最初よりかなりよくなった。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
import boto3

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


class Email(object):
    def __init__(self, frm, to, subject):
        self.frm = frm
        self.to = to
        self.subject = subject
        self.text = None
        self.attachment = None

    def send(self):
        client = boto3.client(
            "ses",
            aws_access_key_id="YourAccessKey",
            aws_secret_access_key="YourSecretKey",
            region_name="us-west-2",
        )

        # メール送信
        msg = MIMEMultipart()
        msg["Subject"] = self.subject
        msg["From"] = self.frm
        msg["To"] = self.to

        filepath = "/tmp/attachment.txt"    # 添付ファイルの絶対パス
        part = MIMEApplication(open(filepath, "rb").read())

        part.add_header("Content-Disposition", "attachment", filename="添付ファイル.txt")
        msg.attach(part)

        part = MIMEText("sample mail")      # メッセージBody
        msg.attach(part)

        client.send_raw_email(
            RawMessage={
                "Data": msg.as_string(),
            },
            Destinations=[],
        )


if __name__ == "__main__":
    email = Email(
        frm="from@example.com",
        to="to_1@example.com",
        subject="件名"
    )
    # you could use StringIO.StringIO() to get the file value
    email.send()

受信したメールをみてみると添付ファイル.txtという名前のファイルが添付されていて、中身は指定した/tmp/attachment.txtと一致した。
メールと MIME オブジェクトを作るライブラリを利用してデータを設定し、最後にas_string()`でstringにしてData`に設定するとメールの作成が結構楽になりそう。

公式(https://docs.python.org/ja/3/library/email.mime.html)も参考にすると良さそうだ。

共有

BAMBi
著者
BAMBi
サーバサイド~インフラがメインでフロントも好きです。趣味はアニメ鑑賞、ゲーム、つまみ細工です。