email.mimeで画像を添付して送りたい
python3 sender.py
画像(プロット)を関係者にもメールでお知らせしたいので、Pythonでメールを作成して送信してみました。
メールは定期的に自動送信したいので、スクリプトにしておきます。
メッセージの作成はemail.mimeパッケージに、メールの送信はsmtplibパッケージに任せます。
メッセージを作成したい(email.mime)
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.image import MIMEImage
from email.utils import formatdate
from pathlib import Path
# メールに関する設定
me = "送信元のメールアドレス"
you = "Toアドレス1,Toアドレス2,..."
them = "Bccアドレス1,Bccアドレス2,..."
text = MIMEText("これは本文です\n", "plain", "utf-8")
# メッセージ用オブジェクト
msg = MIMEMultipart()
# ヘッダーセクションを追加
msg["From"] = me
msg["Date"] = formatdate(localtime=True)
msg["To"] = you
msg["Bcc"] = them
msg["Subject"] = "MIMEMultipartを使ってみる"
# 本文を追加
msg.attach(text)
# 画像を添付
fnames = sorted(Path("images/").glob("*.png"))
for fname in fnames:
with open(fname, "rb") as f:
img = f.read()
image = MIMEImage(img, name=fname.name)
msg.attach(image)
email.mimeパッケージには、次のようなモジュールがあります。
-
MIMEMultipart:画像などを添付できるメッセージ用オブジェクトを作成する -
MIMEText:メールの本文オブジェクトを作成する -
MIMEImage:メールに添付する画像オブジェクトを作成する
メッセージ用オブジェクトを作成したい(MIMEMultipart)
msg = MIMEMultipart()
画像などを添付するため、MIMEMultipartオブジェクトを作成します。
このオブジェクトに対して、本文や画像をattachで追加します。
ヘッダーを追加したい(msg["From"]など)
msg["From"] = me
msg["Date"] = formatdate(localtime=True)
メッセージ用オブジェクトは、msg["From"] = meのように、辞書型と同じように扱えます。
日付は、RFC2822に準拠した形式にする必要があります。
formatdate(localtime=True)を使うのが、一番簡単だと思います。
本文を追加したい(MIMEText)
text = MIMEText("これは本文です\n", "plain", "utf-8")
msg.attach(text)
MIMETextで、プレーンテキストの本文を作成します。
文末には改行コード(\n)をつけておきます。
作成した本文は、メッセージ用オブジェクトに.attachします。
画像を添付したい(MIMEImage)
fnames = sorted(Path("images/").glob("*.png"))
for fname in fnames:
with open(fname, "rb") as f:
img = f.read()
image = MIMEImage(img, name=fname.name)
msg.attach(image)
MIMEImageで、画像オブジェクトを作成します。
画像ファイルのパスはPathオブジェクトで作成し、バイナリ(rb)で開きます。
作成した画像は、メッセージ用オブジェクトに.attachします。
複数の画像を添付するときは、画像ファイルを保存しているディレクトリから、PNG画像の一覧を取得します。
ファイル名の順番にならないことがあったので、sortedしています。
内容を確認したい(print)
msg.items()
[('Content-Type', 'multipart/mixed'),
('MIME-Version', '1.0'),
('From', 'Fromアドレス'),
('Date', 'Wed, 05 Jan 2022 13:29:06 +0900'),
('To', 'Toアドレス1,Toアドレス2,Toアドレス3,...'),
('Bcc', 'Bccアドレス1,Bccアドレス2,Bccアドレス3...'),
('Subject', 'MIMEMultipartを使ってみる')]
msg.items()で、ヘッダーの内容を確認できます。
printすると、メッセージ全体を確認できます。
print(msg)
出力結果
Content-Type: multipart/mixed; boundary="===============3710731288596159002=="
MIME-Version: 1.0
From: =?utf-8?b?RnJvbeOCouODieODrOOCuQ==?=
Date: Wed, 05 Jan 2022 13:29:06 +0900
To: =?utf-8?b?VG/jgqLjg4njg6zjgrkxLFRv44Ki44OJ44Os44K5MixUb+OCouODieODrOOCuTMsLi4u?=
Bcc: =?utf-8?b?QmNj44Ki44OJ44Os44K5MSxCY2PjgqLjg4njg6zjgrkyLEJjY+OCouODieODrOOCuTMuLi4=?=
Subject: =?utf-8?b?TUlNRU11bHRpcGFydOOCkuS9v+OBo+OBpuOBv+OCiw==?=
--===============3710731288596159002==
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: base64
CuOBk+OCjOOBr+acrOaWh+OBp+OBme+8iDHooYznm67vvIkK44GT44KM44Gv5pys5paH44Gn44GZ
77yIMuihjOebru+8iQrjgZPjgozjga/mnKzmlofjgafjgZnvvIgz6KGM55uu77yJCgo=
--===============3710731288596159002==
Content-Type: image/png; name="age_address.png"
MIME-Version: 1.0
Content-Transfer-Encoding: base64
iVBORw0KGgoAAAANSUhEUgAAAowAAAJ7CAYAAABppMB3AAAgAElEQVR4XuydB5RU1fL1S3nkoCCI
...(画像データの部分はとても長いので省略)...
Tw/BIYAAAggggAACrhcgYXT9HBABAggggAACCCBgtcD/ADLCLHirTzJQAAAAAElFTkSuQmCC
--===============3710731288596159002==
Content-Type: image/png; name="age_gender.png"
MIME-Version: 1.0
Content-Transfer-Encoding: base64
iVBORw0KGgoAAAANSUhEUgAAAowAAAJ7CAYAAABppMB3AAAgAElEQVR4XuydC3gV1dW/V0K4RQgX
...(画像データの部分はとても長いので省略)...
LSABEiABEiABEiABpwn8P1SdUGsvHrDXAAAAAElFTkSuQmCC
--===============3710731288596159002==
Content-Type: image/png; name="age_repeat.png"
MIME-Version: 1.0
Content-Transfer-Encoding: base64
iVBORw0KGgoAAAANSUhEUgAAArgAAAJ7CAYAAAAIvOI1AAAgAElEQVR4XuydCXQVRfb/b8IedpR9
...(画像データの部分はとても長いので省略)...
BAAAAABJRU5ErkJggg==
--===============3710731288596159002==--
出力結果から、次のことを確認できました。
- メッセージが
multipart/mixed形式で作成できている - 本文が
text/plain形式で追加できている - 画像3枚を
image/pngで追加できている
ヘッダーセクションに日本語を使ったため、文字がエンコードされています。この点は、さらに確認が必要です。
メールを送信したい(smtplib)
import smtplib
# SMTPサーバの設定
host = "SMTPサーバのアドレス"
port = ポート番号
user = "SMTPサーバのログイン名"
password = "ログインパスワード"
mailer = smtplib.SMTP(host, port)
mailer.set_debuglevel(2)
mailer.starttls()
mailer.ehlo()
mailer.login(user, password)
mailer.send_message(msg)
mailer.quit()
smtplibで、作成したメッセージ用オブジェクト(msg)をメールとして送信します。
処理の流れは、次の通りです。
-
starttls:SMTPサーバーにTLSを使って接続する -
ehlo:SMTPの拡張機能を使うことを明示する -
login:ユーザー名とパスワードで認証する -
send_message:作成したメッセージ用オブジェクト(msg)を受け取って、メールを送信する -
quit:接続を終了する
実行したい(sender.py)
$ python3 sender.py
メッセージを作成する部分と、メールを送信する部分を、1つのファイル(sender.py)にまとめて実行します。
まとめ
email.mimeパッケージを使うことで、とても簡単にメール本文を作成できました。
smtplibパッケージを使うことで、あっさりとメールを送信できました。
MIMEApplicationやMIMEAudioなど、他のモジュールもあるので、添付したいファイルの形式に応じて使い分ければよさそうです。
crontabやwatchdogと組み合わせれば、定期的に実行することもできそうです。
リファレンス
Discussion