概要(Pythonでメール送信は「smtplib+EmailMessage」が基本の型)
Python標準のsmtplibとemailパッケージを使えば、テキストメール、HTMLメール、添付ファイル、複数宛先、CC/BCCまで短いコードで送れます。重要なのは、SMTPサーバ設定(ホスト・ポート・認証・暗号化)、メッセージの正しい組み立て(ヘッダー・本文・MIME)、文字コード(UTF-8)と日本語対応、そしてエラー時の例外処理です。まずは「最短の送信」を動かし、次にHTML・添付・複数宛先へ広げ、最後に安全運用(認証情報の隠し方・失敗時の再試行)を押さえましょう。
仕組みと準備(SMTPの要点と使うモジュール)
SMTPの基本とポートの考え方
メールはSMTPサーバ経由で送信します。通常はSTARTTLSの587番ポート(平文で接続→TLS開始)、もしくはSMTPSの465番ポート(TLSで最初から暗号化)を使います。社内サーバやGmailなど、利用するSMTPのホスト名・ポート・認証方式を事前に確認します。
使うモジュール(smtplib+email)
送信はsmtplib、メッセージの組み立てはemail.message.EmailMessageやemail.mime.*を使います。EmailMessageはヘッダー、本文、添付を扱いやすく、初心者でも間違いが起きにくい選択です。
基本のテキストメール(最短で「届く」形)
EmailMessage+STARTTLSの基本形
import smtplib
from email.message import EmailMessage
SMTP_HOST = "smtp.example.com"
SMTP_PORT = 587 # STARTTLS
USERNAME = "user@example.com"
PASSWORD = "your_app_password" # 本番は環境変数で渡すのが安全
msg = EmailMessage()
msg["Subject"] = "テストメール"
msg["From"] = USERNAME
msg["To"] = "to@example.com"
msg.set_content("これはPythonから送信したテキストメールです。", charset="utf-8")
with smtplib.SMTP(SMTP_HOST, SMTP_PORT, timeout=15) as server:
server.starttls() # 暗号化開始(STARTTLS)
server.login(USERNAME, PASSWORD)
server.send_message(msg)
Python最短でも「From/To/Subject」「本文」「認証」「暗号化」の4点が揃っていれば十分に届きます。文字化けを避けるため、本文はUTF-8を明示します。
SSLポート(465)を使う場合
import smtplib
from email.message import EmailMessage
SMTP_HOST = "smtp.example.com"
SMTP_PORT = 465 # SMTPS
msg = EmailMessage()
msg["Subject"] = "SSLで送信"
msg["From"] = "user@example.com"
msg["To"] = "to@example.com"
msg.set_content("465番ポートでSSL接続から送信します。", charset="utf-8")
with smtplib.SMTP_SSL(SMTP_HOST, SMTP_PORT, timeout=15) as server:
server.login("user@example.com", "your_app_password")
server.send_message(msg)
Python465ではSMTP_SSLを使い、starttlsは不要です。
HTMLメールと日本語(見やすく、崩れない作り)
HTMLだけの送信(シンプル版)
from email.message import EmailMessage
import smtplib
msg = EmailMessage()
msg["Subject"] = "HTMLメールのテスト"
msg["From"] = "user@example.com"
msg["To"] = "to@example.com"
msg.add_alternative("""\
<!doctype html>
<html lang="ja">
<body>
<h1>こんにちは</h1>
<p>これは <strong>HTML</strong> メールです。</p>
</body>
</html>
""", subtype="html")
with smtplib.SMTP("smtp.example.com", 587) as s:
s.starttls()
s.login("user@example.com", "your_app_password")
s.send_message(msg)
Pythonテキスト+HTMLのマルチパート(受信側の互換性を最大化)
from email.message import EmailMessage
import smtplib
msg = EmailMessage()
msg["Subject"] = "マルチパート(text+html)"
msg["From"] = "user@example.com"
msg["To"] = "to@example.com"
msg.set_content("これはテキスト版です。HTMLが読めない環境でも安心。", charset="utf-8")
msg.add_alternative("""\
<html><body>
<p>これはHTML版です。<br>見た目が整ったメールを届けます。</p>
</body></html>
""", subtype="html")
with smtplib.SMTP("smtp.example.com", 587) as s:
s.starttls()
s.login("user@example.com", "your_app_password")
s.send_message(msg)
PythonHTMLメールは「テキスト版も同梱」すると、表示互換性が上がります。日本語はUTF-8で統一し、本文や件名に機種依存文字を避けると崩れにくいです。
添付ファイル・複数宛先・CC/BCC(実務でよく使う形)
添付ファイルを付ける
from email.message import EmailMessage
import mimetypes, smtplib
msg = EmailMessage()
msg["Subject"] = "レポート添付"
msg["From"] = "user@example.com"
msg["To"] = "to@example.com"
msg.set_content("レポートを添付します。")
path = "report.pdf"
ctype, encoding = mimetypes.guess_type(path)
maintype, subtype = (ctype.split("/", 1) if ctype else ("application", "octet-stream"))
with open(path, "rb") as f:
msg.add_attachment(f.read(), maintype=maintype, subtype=subtype, filename="report.pdf")
with smtplib.SMTP("smtp.example.com", 587) as s:
s.starttls(); s.login("user@example.com", "your_app_password")
s.send_message(msg)
PythonMIMEタイプはmimetypesで推定し、filenameを付けると受信側で分かりやすくなります。
複数宛先・CC/BCC
from email.message import EmailMessage
import smtplib
to_list = ["a@example.com", "b@example.com"]
cc_list = ["c@example.com"]
bcc_list = ["d@example.com"] # ヘッダーには載せない
msg = EmailMessage()
msg["Subject"] = "複数宛先のテスト"
msg["From"] = "user@example.com"
msg["To"] = ", ".join(to_list)
msg["Cc"] = ", ".join(cc_list)
msg.set_content("ToとCcへ同時送信。Bccはヘッダーに載らない宛先です。", charset="utf-8")
all_rcpts = to_list + cc_list + bcc_list
with smtplib.SMTP("smtp.example.com", 587) as s:
s.starttls(); s.login("user@example.com", "your_app_password")
s.send_message(msg, to_addrs=all_rcpts)
PythonBCCはヘッダーに書かず、SMTP送信時だけ宛先に含めます。
エラー処理・安全運用(失敗しない、漏らさない)
代表的な例外のハンドリング
import smtplib, socket
from email.message import EmailMessage
try:
msg = EmailMessage()
msg["Subject"] = "送信テスト"
msg["From"] = "user@example.com"
msg["To"] = "to@example.com"
msg.set_content("本文", charset="utf-8")
with smtplib.SMTP("smtp.example.com", 587, timeout=15) as s:
s.starttls()
s.login("user@example.com", "your_app_password")
s.send_message(msg)
except smtplib.SMTPAuthenticationError as e:
print("認証エラー:ユーザー名/パスワード、アプリパスワード設定を確認")
except smtplib.SMTPConnectError as e:
print("接続エラー:ホスト名、ポート、ネットワーク到達性を確認")
except smtplib.SMTPException as e:
print("SMTP一般エラー:", e)
except socket.timeout:
print("タイムアウト:サーバ遅延やファイアウォールを確認")
Pythonsmtplibは認証・接続・一般的SMTP例外のクラスが用意されています。タイムアウトも設定して「待ち続け」を防ぎます。
認証情報の管理(環境変数で隠す)
import os
USERNAME = os.environ["SMTP_USER"]
PASSWORD = os.environ["SMTP_PASS"]
Pythonコードに平文で書かず、環境変数や秘密管理ツールを使います。Gmailなら「アプリパスワード」を発行して使う運用が安全です。
送信の健全性(From/Reply-To、SPF/DKIMの考慮)
Fromは送信者として正しいドメインを使い、必要ならReply-Toで返信先を明示します。外部へ大量配信する場合、SPF/DKIMなど送信ドメイン認証を管理側で設定しておくと迷惑メール判定を避けやすくなります。
例題で身につける(定番から実務まで)
例題1:テキストメール(STARTTLS)
import smtplib
from email.message import EmailMessage
def send_text(to):
msg = EmailMessage()
msg["Subject"] = "最短テキストメール"
msg["From"] = "user@example.com"
msg["To"] = to
msg.set_content("こんにちは。Pythonからのメールです。", charset="utf-8")
with smtplib.SMTP("smtp.example.com", 587, timeout=10) as s:
s.starttls()
s.login("user@example.com", "your_app_password")
s.send_message(msg)
send_text("to@example.com")
Python例題2:テキスト+HTMLのマルチパート
import smtplib
from email.message import EmailMessage
msg = EmailMessage()
msg["Subject"] = "見やすいHTML+テキスト"
msg["From"] = "user@example.com"
msg["To"] = "to@example.com"
msg.set_content("テキスト版です。", charset="utf-8")
msg.add_alternative("<h1>HTML版です</h1><p>整った見た目で届けます。</p>", subtype="html")
with smtplib.SMTP("smtp.example.com", 587) as s:
s.starttls(); s.login("user@example.com", "your_app_password")
s.send_message(msg)
Python例題3:添付ファイル+複数宛先(CC/BCC)
import smtplib, mimetypes
from email.message import EmailMessage
msg = EmailMessage()
msg["Subject"] = "週次レポート"
msg["From"] = "user@example.com"
msg["To"] = "a@example.com, b@example.com"
msg["Cc"] = "c@example.com"
msg.set_content("レポート添付します。", charset="utf-8")
ctype, _ = mimetypes.guess_type("report.xlsx")
maintype, subtype = (ctype.split("/", 1) if ctype else ("application", "octet-stream"))
with open("report.xlsx", "rb") as f:
msg.add_attachment(f.read(), maintype=maintype, subtype=subtype, filename="report.xlsx")
recipients = ["a@example.com", "b@example.com", "c@example.com", "d@example.com"] # dはBCC
with smtplib.SMTP("smtp.example.com", 587) as s:
s.starttls(); s.login("user@example.com", "your_app_password")
s.send_message(msg, to_addrs=recipients)
Python例題4:安全運用(環境変数+例外処理のひな形)
import os, smtplib, socket
from email.message import EmailMessage
SMTP_HOST = os.getenv("SMTP_HOST", "smtp.example.com")
SMTP_PORT = int(os.getenv("SMTP_PORT", "587"))
USERNAME = os.environ["SMTP_USER"]
PASSWORD = os.environ["SMTP_PASS"]
msg = EmailMessage()
msg["Subject"] = "安全運用のひな形"
msg["From"] = USERNAME
msg["To"] = "to@example.com"
msg.set_content("例外処理と環境変数を組み込んだ送信例。", charset="utf-8")
try:
with smtplib.SMTP(SMTP_HOST, SMTP_PORT, timeout=15) as s:
s.starttls()
s.login(USERNAME, PASSWORD)
s.send_message(msg)
except (smtplib.SMTPException, socket.timeout) as e:
print("送信失敗:", e)
Pythonまとめ
Pythonでのメール送信は、smtplib(接続・送信)とEmailMessage(組み立て)が基本です。まずテキストの最短送信を確実にし、次にHTMLとテキストのマルチパート、添付、複数宛先、CC/BCCを広げます。日本語はUTF-8で統一し、ポートと暗号化(587+STARTTLS、または465+SSL)を正しく選択。認証情報は環境変数で隠し、タイムアウトと例外を必ず入れて「落ちない・漏らさない」運用にする。これらの型を身につければ、初心者でも短いコードで実務品質のメール送信が書けます。
