【Python】smtplibでメール送信してみる

Python

概要

Pythonの標準ライブラリであるsmtplibを使用してメールを送信するコードの例です。今回使用する私のメールサーバーがTLS通信(SSL)をサポートしたものであるため、TLS通信で、かつ認証を行う場合の例となっています。

なお、Pythonのバージョンは3.9を使用しています。

コード

import smtplib
from email.mime.text import MIMEText

# 送受信先
to_addr = "送信先アドレス"
from_addr = "送信元アドレス"

msg = MIMEText('本文', "plain", 'utf-8')
msg['Subject'] = "メールのタイトル"
msg['From'] = from_addr
msg['To'] = to_addr

with smtplib.SMTP_SSL(host="host name", port=465) as smtp:
    smtp.login('user', 'pass')
    smtp.send_message(msg)
    smtp.quit()

コードの解説

方法としては、

  1. MIMETextクラスでMessageオブジェクトを作成
  2. SMTP_SSLオブジェクトを作成
  3. .login()でログイン
  4. .send_message()で送付
  5. .quit()で終了

という流れです。
クラスの関数の使い方さえ分かれば、それほど難しくはないですね。

ちなみに、.sendmail()も送信用の関数ですが、こちらは若干手間で、メールのヘッダーフィールドを文字列で直に書く必要があります。emailのメッセージに関する規約であるRFC 5322に準拠した形式で書かないといけません。

ただ、公式マニュアルの.send_message()の箇所を見ると、”This is a convenience method for calling sendmail() with the message. . .”と書いてあり、.send_message()が便利な方法だと書かれています。こちらを使用したほうが楽でしょう。

ちなみに、SMTP_SSLのコンストラクタとしてportを指定しない場合、自動的に465が使用されるようです(今回は明示的に示している)。

EmailMessage, MIMETextどちらを使用するか

.send_message()では、引数にMessageオブジェクトを渡します。作成方法は、色んなサイトを見るとMIMETextが使用されていますが、ところが、Python公式ドキュメントによるとEmailMessageもあるようです。どちらでもMessageオブジェクトは作成可能のようですが、どう違うのでしょうね?

試しに確認してみましょう。

from email.message import EmailMessage
from email.mime.text import MIMEText

# 送受信先
to_email = "送信先"
from_email = "送信元"

msg = EmailMessage()
msg['Subject'] = "タイトル行"
msg['From'] = from_email
msg['To'] = to_email
msg.set_content('本文')

msg_mime = MIMEText('本文', "plain", 'utf-8')
msg_mime['Subject'] = "タイトル行"
msg_mime['From'] = from_email
msg_mime['To'] = to_email

[print('{0}: {1}'.format(k,v))  for k,v in msg.items()]
[print('{0}: {1}'.format(k,v))  for k,v in msg_mime.items()]

最後の行で、生成されたヘッダを出力しています。

EmailMessageを使用した場合、Content-Transfer-Encoding8bitになっていますね。

Subject: タイトル行
From: 送信元
To: 送信先
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: 8bit
MIME-Version: 1.0

それに対し、MIMETextは次のようでした。Content-Transfer-Encodingbase64です。

Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: base64
Subject: タイトル行
From: 送信元
To: 送信先

メールのエンコードには、通常、base64が使用されますね。
エンコードは設定で変更できると思うのですが、今回はそこまでは調べていません。

基底クラスを確認してみる

EmailMessageクラス、MIMETextクラスの基底クラスを確認してみましょう。継承元のクラスを調べるにはinspectモジュールの.getmro()が使えます。

import inspect
inspect.getmro(EmailMessage)
inspect.getmro(MIMEText)

EmailMessageです。

[print(r) for r in inspect.getmro(EmailMessage)]

<class 'email.message.EmailMessage'>
<class 'email.message.MIMEPart'>
<class 'email.message.Message'>
<class 'object'>

MIMETextはこちら。どちらも、基底クラスにMessageクラスがあります(当たり前だけど)。

<class 'email.mime.text.MIMEText'>
<class 'email.mime.nonmultipart.MIMENonMultipart'>
<class 'email.mime.base.MIMEBase'>
<class 'email.message.Message'>
<class 'object'>

以上です。