Python3.5 + SMTPで、Gmailからメールを送信しようと考え調べてみたところ、Web上には色々な書き方がありました。
自分なりにいろいろと手を動かしてみて、Pythonの標準ライブラリであるsmtplib.SMTP_SSL.send_message()
に行き着いた時のメモを残します。
ただ、自分なりの調査のため、もし誤りなどがあればご指摘いただけるとありがたいです。
なお、MIMETextの設定など、どのような書き方でも変わらない部分は、
import sys import smtplib from email.mime.text import MIMEText from email.utils import formatdate ACCOUNT = "example@gmail.com" ALIAS = "example+alias@gmail.com" PASSWORD = "passw0rd" def create_message(subject): msg = MIMEText("Body: Hello world!") msg["Subject"] = subject msg["From"] = ACCOUNT msg["To"] = ALIAS msg["Date"] = formatdate(localtime=True) return msg
のような定数・関数を用意しています。
実際にテストするときは、定数の値を自分のアカウント情報へと変更します。
目次
- 環境
- MIMETextのimportについて
- SMTPオブジェクトを使う実装
- SMTP_SSLオブジェクトを使う実装
- sendmail()の代わりにsend_message()を使う実装
- ソースコード
- 参考
環境
- Windows10 x64
- Python 3.5.1 32bit
今回、
を行います。
また、どのコードから送信されたのかを分かりやすくするため、送信処理を行った関数名をメールのSubjectに入れました。
実行中の関数・メソッド名を取得したい - Qiita
ほかに、GitHub上のソースコードを行数付で参照していますが、masterだと行数が変わってしまうおそれがあるため、適当な最近のコミットを指定しています。
MIMETextのimportについて
MIMETextのimportでは2つの方法を見かけたため、両方を試してみたところ、
from email.MIMEText import MIMEText # => ImportError: No module named 'email.MIMEText' from email.mime.text import MIMEText # => OK
前者ではImportErrorになりました。
ソースコードを見たところ、Python2.7系ではモジュールがあったものの、Python3.5系では削除されていました。
ちなみに、from email.mime.text import MIMEText
は、Python2.7系でも使えそうでした。
SMTPオブジェクトを使う実装
starttls()の前後で、ehlo()を呼ぶ実装
公式ドキュメントを読むと、helo()
やconnect()
は不要そうだったので、それらのメソッドは使いませんでした。
- SMTP.helo() - 21.17. smtplib — SMTP プロトコルクライアント — Python 3.5.1 ドキュメント
- SMTP.connect() - 21.17. smtplib — SMTP プロトコルクライアント — Python 3.5.1 ドキュメント
また、終了するときに、close()
とquit()
、どちらを使えば良いのか分かりませんでした。ただ、
- 公式ドキュメントには
close()
の記載なし - ソースコードを読んだところ、
quit()
の中でclose()
を呼んでいた
ということから、quit()
を使うのが良さそうでした。
msg = create_message(sys._getframe().f_code.co_name) s = smtplib.SMTP("smtp.gmail.com", 587) s.ehlo() s.starttls() s.ehlo() s.login(ACCOUNT, PASSWORD) s.sendmail(ACCOUNT, ALIAS, msg.as_string()) s.quit()
ehlo()を使わない実装
starttls()の前後でehlo()
を呼ぶ必要があるのかを調べたところ、
ということから、必要なさそうでした。
msg = create_message(sys._getframe().f_code.co_name) s = smtplib.SMTP("smtp.gmail.com", 587) s.starttls() s.login(ACCOUNT, PASSWORD) s.sendmail(ACCOUNT, ALIAS, msg.as_string()) s.quit() print("finished: {}".format(sys._getframe().f_code.co_name))
SMTP_SSLオブジェクトを使う実装
starttls()
メソッドでSTARTTLS
コマンドを使って暗号化をしていました。ただ、Web上のいくつかのサンプルでは、SMTP_SSL
オブジェクトを使っていました。
class smtplib.SMTP_SSL - 21.17. smtplib — SMTP プロトコルクライアント — Python 3.5.1 ドキュメント
SMTP_SSLクラスのソースコードを見たところ、
でした。
SMTP_SSLを使った場合、以下のような実装となりました。
msg = create_message(sys._getframe().f_code.co_name) s = smtplib.SMTP_SSL("smtp.gmail.com") s.login(ACCOUNT, PASSWORD) s.sendmail(ACCOUNT, ALIAS, msg.as_string()) s.quit() print("finished: {}".format(sys._getframe().f_code.co_name))
sendmail()の代わりにsend_message()を使う実装
MIMETextでFromやToを設定しているのにもかかわらず、sendmail()
の引数にもFromやToを渡す必要があります。
良い方法がないかを調べたところ、Python3.2から追加されたsend_message()
がありました。
SMTP.send_message - 21.17. smtplib — SMTP プロトコルクライアント — Python 3.5.1 ドキュメント
ソースコードを見たところ、内部でsendmail()
を呼んでいたため、これを使うのが良さそうでした。
msg = create_message(sys._getframe().f_code.co_name) s = smtplib.SMTP_SSL("smtp.gmail.com") s.login(ACCOUNT, PASSWORD) s.send_message(msg) s.quit() print("finished: {}".format(sys._getframe().f_code.co_name))
最初のものに比べるとかなり短くなりました。
なお、SMTPオブジェクトを使う場合でもsend_message()
は使えます。
ソースコード
GitHubに上げました。
thinkAmi-sandbox/smtplib-sample
参考
SMTPまわりのPythonでの経緯とかが分かりやすく書かれていました。
プログラミングと慶應通信 : Pythonでgmailの送受信
受信側はこちらのコードが参考になりそうです。
Python でメール送受信(Gmail で SMTP と IMAP を使う場合) - akiyoko blog
なお、GmailにはAPIもあり、Pythonライブラリも用意されています。
Gmail API Client Library for Python | API Client Library for Python | Google Developers
公式ドキュメントで役立ちそうなのも載せておきます。