【Python】smtplibとEmailMessageでメールを送信する:HTMLメール対応

目次

概要

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 オブジェクトを解析し、適切なフォーマットでメールを送信します。

注意点

  1. セキュリティとパスワード管理
    • スクリプト内にパスワードを直書きするのは危険です。環境変数(os.environ)や外部の設定ファイルから読み込むようにしてください。
    • Gmailを使用する場合、2段階認証を有効にした上で「アプリパスワード」を発行して使用する必要があります(通常のログインパスワードでは弾かれます)。
  2. ポート番号の使い分け
    • 587: SMTP("host", 587) -> starttls() の順で使用(推奨)。
    • 465: smtplib.SMTP_SSL("host", 465) を使用し、最初からSSL接続する場合。
  3. 送信制限
    • フリーメールの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 を使用して、接続管理とエラー処理を適切に行いましょう。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

私が勉強したこと、実践したこと、してることを書いているブログです。
主に資産運用について書いていたのですが、
最近はプログラミングに興味があるので、今はそればっかりです。

目次