📫

email.mimeで画像を添付して送りたい

2021/01/26に公開

動機

  • 画像(プロット)を関係者にもメールでお知らせしたい
  • メールは定期的に自動送信したい
  • email.mime パッケージを使ってメールを作成してみる

メッセージの作成

  • メッセージの作成は部分は email.mime.*パッケージに任せる

https://docs.python.org/ja/3/library/email.mime.html

メッセージ用オブジェクトの作成
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)
メッセージ用オブジェクトの内容
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を使ってみる')]
メッセージ用オブジェクトの内容
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 で追加できている

さらに確認が必要なこと

  • ヘッダーセクションに日本語を使ったので文字がエンコードされてる

メッセージ作成のまとめ

モジュールの役割

  1. MIMEMultipart : 画像などを添付できるメッセージ用オブジェクトの作成
  2. MIMEText : メールの本文オブジェクトの作成
  3. MIMEImage : メールに添付する画像オブジェクトの作成

メッセージ用オブジェクトの作成

  • 画像などを添付するため MIMEMultipartオブジェクトを作成した
  • このオブジェクトに対して本文/画像を attachで追加する

ヘッダーセクションの追加

  • メッセージ用オブジェクトは msg["From"] = me のように辞書型と同じように扱うことができる
  • 日付は RFC2822 準拠の形式にする必要がある。formatdate(localtime=True)を使うのが一番簡単だと思う

本文オブジェクトの追加

  • MIMETextを使ってプレーンテキストを作成する
  • 文末に改行コード(\n)をつける
  • メッセージ用オブジェクトに.attachする

画像オブジェクトの追加

  • MIMEImageを使って画像ファイルを作成する
  • 画像ファイルのパスはPathオブジェクトで作成した
  • 画像ファイルはバイナリ(rb)で開く
  • メッセージ用オブジェクトに.attachする

複数の画像を添付

  • 画像ファイルを保存しているディレクトリから PNG 画像の一覧を取得する
  • ファイル名の順番にならないことがあったのでsortedする

メールの送信

  • メールの送信はsmtplibパッケージに任せる

https://docs.python.org/ja/3/library/smtplib.html

sender.py
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()

メール送信のまとめ

  1. SMTP サーバに TLS を使って接続する
  2. ユーザ名・パスワードを使って認証する
  3. SMTP の拡張機能を使うことを明示する
  4. 作成したメッセージ用オブジェクト(msg)を受け取る
  5. SMTP を使ってメールを送信する

まとめ

  • メッセージ作成の部分と、メール送信の部分を一つのファイル(sender.py)にまとめる
  • 下記のコマンドを実行する
メールを送信
$ python3 sender.py

感想

  1. email.mimeパッケージを使うことで、とても簡単にメール本文を作成することができた
  2. MIMEApplicationMIMEAudioなど、他のモジュールもあるので、添付したいファイルの形式に応じて使い分ければよさそう
  3. smtplibパッケージを使うことで、あっさりとメールを送信することができた
  4. crontabwatchdog と組み合わせて、定期実行できそう

Discussion