メールを送る

Pythonでメールを送るのは、Webページ監視で使ったようなローカルのSMTPサーバで送る方法なら簡単だが、ここではiCloudのようなリモートのSMTPサーバにTLSで接続して送る方法を説明する。

Appleのほかのメールクライアント App 向けの iCloud メールサーバ設定という説明を読んで、まずはApp用パスワードを設定する。ユーザ名は、iCloudのメインの user@icloud.com の形式のメールアドレスである。

メールを組み立てるのは email モジュール、SMTPで送るのは smtplib モジュール、SSL/TLSは ssl モジュールを使う。いずれもPython標準ライブラリに含まれる。特にSSLの Security considerations のBest defaultsを参考にした。

from email.message import EmailMessage
import smtplib
import ssl

# メールを組み立てる
msg = EmailMessage()
msg['From'] = "差出人メアド"
msg['To'] = "宛先メアド"
msg['Subject'] = "件名"
msg.set_content("""本文1行目
本文2行目
""")

# メールを送る
with smtplib.SMTP("smtp.mail.me.com", 587) as smtp:
    context = ssl.create_default_context()
    smtp.starttls(context=context)
    smtp.login("user@icloud.com", "password")
    smtp.send_message(msg)

メールがどのように組み立てられたかは次のようにしてみればわかる。

print(msg.as_string())

smtp.starttls() がうまくいくと (220, b'2.0.0 Ready to start TLS') が返る。さらに smtp.login() がうまくいくと (235, b'2.7.0 Authentication successful') が返る。ユーザ名かパスワードが間違っていると SMTPAuthenticationError: (535, b'5.7.8 Error: authentication failed') が返る。メールを送り終わると (221, b'2.0.0 Bye') が返る。

ループで多人数に送る場合は次のようになりそうである。

from email.message import EmailMessage
import smtplib
import ssl
import time

# 1. 送信先リスト(実際はCSVやDBから読み込むのがよさそう)
# (名前, メールアドレス) のタプル形式
recipients = [
    ("山田 太郎", "yamada@example.com"),
    ("佐藤 花子", "sato@example.com"),
    # ...
]

FROM_ADDRESS = "user@icloud.com"
PASSWORD = "password"

# 2. SSL/TLSのコンテキスト準備
context = ssl.create_default_context()

# 3. SMTP接続をループの外で確立
print("SMTPサーバーに接続中...")
with smtplib.SMTP("smtp.mail.me.com", 587) as smtp:
    smtp.starttls(context=context)
    smtp.login(FROM_ADDRESS, PASSWORD)
    print("ログイン成功。配信を開始します。")

    # 4. ループ処理で1人ずつ送信
    for name, to_address in recipients:
        try:
            # メールの組み立て
            msg = EmailMessage()
            msg['From'] = FROM_ADDRESS
            msg['To'] = to_address
            msg['Subject'] = "【重要】大切なお知らせ"
            
            # 本文に名前を差し込む
            body = f"""{name} 様

いつも大変お世話になっております。
(ここにメールの本文を記述)
"""
            msg.set_content(body)

            # 送信
            smtp.send_message(msg)
            print(f"送信成功: {to_address}")

            # 5. 送信間隔を空ける
            time.sleep(2)  # 2〜5秒

        except Exception as e:
            # エラーが発生しても止めず、ログに残して次へ進む
            print(f"【エラー】送信失敗: {to_address} - 理由: {e}")
            continue

print("すべての送信処理が完了しました。")

1日あたり1000人まで・1000通まで、1通あたり50人までが限度。それ以上は外部サービスを利用するのがよい。