目次
概要
Python標準ライブラリの smtplib と email.message モジュールを使用して、メールを送信する方法を解説します。
従来の複雑な MIMEText などを使用せず、Python 3.6以降で推奨されるモダンで扱いやすい EmailMessage クラスを使用した実装を紹介します。プレーンテキストだけでなく、HTML形式のメール送信もカバーします。
仕様(入出力)
- 入力:
- 送信元アドレス (From)
- 送信先アドレス (To)
- SMTPサーバーの設定(ホスト、ポート、認証情報)
- メール件名・本文(テキストまたはHTML)
- 出力:
- SMTPサーバー経由でのメール送信実行
- 成功・失敗のログ出力
基本の使い方
最もシンプルなプレーンテキストメールを送信する例です。
with 文を使用することで、SMTP接続の終了処理(quit)を自動化しています。
import smtplib
from email.message import EmailMessage
# メッセージの作成
msg = EmailMessage()
msg["Subject"] = "Hello Python"
msg["From"] = "sender@example.com"
msg["To"] = "receiver@example.com"
msg.set_content("これはPythonからのテストメールです。")
# 送信処理 (設定は環境に合わせて変更してください)
# ローカルのテスト用サーバー(localhost:1025)などを想定
with smtplib.SMTP("localhost", 1025) as smtp:
smtp.send_message(msg)
コード全文
HTML形式の本文を含み、テキスト形式とのマルチパート(受信環境に応じた表示切り替え)に対応した、実用的なメール送信関数です。GmailのSMTPサーバーを使用する設定例として記述しています。
import smtplib
from email.message import EmailMessage
import ssl
def send_html_email():
"""
HTML形式のメールを送信するデモ関数。
HTML非対応のメーラーのためにプレーンテキストも設定します。
"""
# 1. 設定値(実際には環境変数などで管理することを推奨)
smtp_host = "smtp.gmail.com"
smtp_port = 587
my_email = "your_email@gmail.com"
my_password = "your_app_password" # アプリパスワード等
to_email = "target_address@example.com"
# 2. EmailMessageオブジェクトの生成とヘッダー設定
msg = EmailMessage()
msg["Subject"] = "【お知らせ】PythonからのHTMLメール"
msg["From"] = my_email
msg["To"] = to_email
# 3. 本文の設定(マルチパート構成)
# まず、HTML非対応環境用のプレーンテキストを設定
text_content = "こんにちは。\nこれはHTML形式のメールです。\n対応環境でご覧ください。"
msg.set_content(text_content)
# 次に、HTML本文を追加(add_alternative)
# これにより、受信側で優先的にHTMLが表示されます
html_content = """
<html>
<body>
<h1 style="color: #2E86C1;">HTML Email Test</h1>
<p>Pythonの<b>EmailMessage</b>クラスを使用しています。</p>
<p>リンク: <a href="https://www.python.org">Python.org</a></p>
</body>
</html>
"""
msg.add_alternative(html_content, subtype="html")
# 4. SMTPサーバーへ接続して送信
try:
# ポート587の場合は starttls() を使用するのが一般的
print("SMTPサーバーへ接続中...")
with smtplib.SMTP(smtp_host, smtp_port) as smtp:
# サーバーとのやり取りを確認したい場合はデバッグレベルを上げる
# smtp.set_debuglevel(1)
# 暗号化通信の開始
context = ssl.create_default_context()
smtp.starttls(context=context)
# ログイン
smtp.login(my_email, my_password)
# 送信
smtp.send_message(msg)
print("メールが正常に送信されました。")
except smtplib.SMTPAuthenticationError:
print("認証エラー: メールアドレスまたはパスワードが間違っています。")
except Exception as e:
print(f"送信エラーが発生しました: {e}")
if __name__ == "__main__":
send_html_email()
カスタムポイント
EmailMessage型オブジェクトの生成と操作
email.message モジュールの主要メソッドです。
| 構文 | 意味・処理 |
msg = EmailMessage() | 新しい空のメールメッセージオブジェクトを生成します。辞書のようにヘッダー(Subject, From, To)を設定できます。 |
msg.set_content(本文) | メールのメイン本文を設定します。デフォルトはプレーンテキスト(text/plain)として扱われます。 |
msg.add_alternative(本文, subtype="html") | マルチパートメッセージとして、代替の表現(HTML版など)を追加します。set_content の後に実行することで、HTML対応メーラーではこちらが表示されます。 |
smtplib.SMTPオブジェクトの生成と操作
smtplib モジュールの主要メソッドです。
| 構文 | 意味・処理 |
smtplib.SMTP(HOST, PORT) | SMTPサーバーへの接続オブジェクトを生成します。ポートは通常 587(STARTTLS)または 25(非暗号化/ローカル)を指定します。 |
smtp.starttls() | 接続をTLS(Transport Layer Security)モードに切り替え、通信経路を暗号化します。認証情報を送る前に実行必須です。 |
smtp.login(EMAIL, PASS) | SMTPサーバーに認証情報を送信してログインします。Gmail等の場合、通常のパスワードではなく「アプリパスワード」が必要な場合があります。 |
smtp.send_message(msg) | 作成した EmailMessage オブジェクトを解析し、適切なフォーマットでメールを送信します。 |
注意点
- セキュリティとパスワード管理
- スクリプト内にパスワードを直書きするのは危険です。環境変数(
os.environ)や外部の設定ファイルから読み込むようにしてください。 - Gmailを使用する場合、2段階認証を有効にした上で「アプリパスワード」を発行して使用する必要があります(通常のログインパスワードでは弾かれます)。
- スクリプト内にパスワードを直書きするのは危険です。環境変数(
- ポート番号の使い分け
- 587:
SMTP("host", 587)->starttls()の順で使用(推奨)。 - 465:
smtplib.SMTP_SSL("host", 465)を使用し、最初からSSL接続する場合。
- 587:
- 送信制限
- フリーメールのSMTPサーバーには、1日あたりの送信数制限やスパム判定フィルタがあります。大量送信(メルマガ等)には向きません。
応用
EmailMessage を使うと添付ファイルも簡単に追加できます。
import mimetypes
# (msg作成等のコードは省略)
# 添付したいファイル
file_path = "report.pdf"
with open(file_path, "rb") as f:
file_data = f.read()
file_name = f.name
# MIMEタイプを自動判定
maintype, subtype = mimetypes.guess_type(file_name)[0].split("/")
# 添付ファイルを追加
msg.add_attachment(
file_data,
maintype=maintype,
subtype=subtype,
filename=file_name
)
まとめ
Pythonでのメール送信は、EmailMessage クラスの登場により非常に直感的になりました。
テキストのみであれば set_content、HTMLメールなら add_alternative を組み合わせることで、ほとんどの用途に対応できます。送信時は with 文と try-except を使用して、接続管理とエラー処理を適切に行いましょう。
