目次
概要
Python標準ライブラリ email.message を使用して、PDFや画像などのファイルを添付したメールを作成・送信する方法を解説します。
添付ファイルのデータ形式(MIMEタイプ)を mimetypes モジュールで自動判定させることで、様々な種類のファイルを汎用的に扱える実装を紹介します。
仕様(入出力)
- 入力:
- 送信元・送信先情報、件名、本文
- 添付したいファイルのパス
- 出力:
- 添付ファイルが含まれたメールメッセージオブジェクトの生成
- SMTPサーバーへの送信
- 前提:
- 送信可能なSMTPサーバー環境(Gmailなど)があること。
- ファイルが存在し、読み取り可能であること。
基本の使い方
ファイルをバイナリモードで読み込み、MIMEタイプを特定してからメールオブジェクトに追加する基本的な手順です。
from email.message import EmailMessage
import mimetypes
msg = EmailMessage()
msg.set_content("ファイルを添付します。")
file_path = "report.pdf"
# ファイルのMIMEタイプ(種類)を推測
ctype, encoding = mimetypes.guess_type(file_path)
if ctype is None:
ctype = "application/octet-stream" # 不明な場合のデフォルト
maintype, subtype = ctype.split("/", 1)
# ファイルを読み込んで添付
with open(file_path, "rb") as f:
file_data = f.read()
msg.add_attachment(
file_data,
maintype=maintype,
subtype=subtype,
filename=f.name
)
コード全文
添付ファイル付きメールを作成し、ローカルのSMTPサーバー(テスト用)へ送信する完全な実装例です。
実運用時はSMTPホスト設定をGmail等に変更してください。
import smtplib
import mimetypes
import os
from email.message import EmailMessage
def send_email_with_attachment():
"""
ファイルを添付してメールを送信するデモ関数。
"""
# 1. メール情報の作成
msg = EmailMessage()
msg["Subject"] = "【日報】添付ファイル送付の件"
msg["From"] = "myself@example.com"
msg["To"] = "boss@example.com"
msg.set_content("お疲れ様です。\n本日の報告書を添付いたします。\nご確認ください。")
# 2. 添付ファイルの処理
# 例として同じディレクトリにある画像ファイルを想定
target_file = "monthly_chart.png"
# ファイルが存在するか確認(エラー回避)
if not os.path.exists(target_file):
print(f"エラー: ファイル '{target_file}' が見つかりません。")
return
# MIMEタイプの判定
mime_type, _ = mimetypes.guess_type(target_file)
if mime_type is None:
# 判定できない場合は一般的なバイナリデータとして扱う
mime_type = "application/octet-stream"
# type/subtype に分割 (例: image/png -> main=image, sub=png)
main_type, sub_type = mime_type.split("/", 1)
try:
with open(target_file, "rb") as f:
file_data = f.read()
file_name = os.path.basename(target_file)
# メッセージに添付データを追加
msg.add_attachment(
file_data,
maintype=main_type,
subtype=sub_type,
filename=file_name
)
print(f"ファイルを添付しました: {file_name} ({mime_type})")
# 3. SMTP送信処理
# ここではローカルのテストサーバー(localhost:1025)を指定
# 本番環境では smtp.gmail.com:587 などを使用
smtp_host = "localhost"
smtp_port = 1025
print("メールを送信中...")
with smtplib.SMTP(smtp_host, smtp_port) as smtp:
# smtp.starttls() # 必要に応じて有効化
# smtp.login("user", "pass") # 必要に応じて有効化
smtp.send_message(msg)
print("送信完了しました。")
except Exception as e:
print(f"送信中にエラーが発生しました: {e}")
if __name__ == "__main__":
# テスト用ファイルを作成して実行(動作確認用)
with open("monthly_chart.png", "wb") as f:
f.write(b"Dummy Image Data")
send_email_with_attachment()
# 掃除
os.remove("monthly_chart.png")
カスタムポイント
添付ファイル処理に関連する主要なメソッドとモジュールの仕様です。
MIMEタイプの判定 (mimetypes)
| 構文 | 意味・処理 |
mimetypes.guess_type(path) | ファイルパス(拡張子)に基づいて、MIMEタイプとエンコーディングのタプル (type, encoding) を返します。例: 'document.pdf' → ('application/pdf', None) |
添付ファイルの追加 (EmailMessage)
| パラメータ | 意味・設定内容 |
data (第1引数) | ファイルの中身そのものであるバイナリデータ(f.read() の戻り値)。 |
maintype | MIMEタイプのメインカテゴリ。 例: image, application, text |
subtype | MIMEタイプのサブカテゴリ。 例: jpeg, pdf, plain |
filename | メール受信側で表示されるファイル名。 |
解説
mimetypesの利点: 拡張子ごとにif ext == '.jpg': ...といった分岐を書く必要がなくなり、コードが汎用的になります。application/octet-stream: 拡張子から種類が特定できなかった場合に使用する「任意のバイナリデータ」を示す汎用タイプです。これを設定しておけば、少なくとも受信側でダウンロード可能なファイルとして扱われます。
注意点
- ファイルサイズ制限
- 多くのメールサーバー(Gmail等)には、添付ファイルを含めたメール全体のサイズ上限(例: 25MB)があります。
- 動画や高解像度画像を送る場合は、Python側でエラーが出る前にサーバー側で拒否される可能性があります。
- ファイルパスとファイル名
filename引数には、フルパスではなくファイル名のみ(os.path.basename使用)を渡すのがマナーです。フルパスを渡すと、受信者の環境によってはセキュリティ警告が出たり、ファイル名が正しく表示されないことがあります。
- バイナリモード
- 画像やPDFなどの非テキストファイルを扱うため、
open()関数には必ずrb(Read Binary) モードを指定してください。
- 画像やPDFなどの非テキストファイルを扱うため、
応用
フォルダ内のすべてのファイルを一括で添付するループ処理の例です。
import os
import mimetypes
from email.message import EmailMessage
def attach_all_files_in_dir(msg, directory):
"""
指定ディレクトリ内の全ファイルをメールに添付します。
"""
for filename in os.listdir(directory):
path = os.path.join(directory, filename)
# ディレクトリはスキップ
if not os.path.isfile(path):
continue
# MIME判定
ctype, encoding = mimetypes.guess_type(path)
if ctype is None or encoding is not None:
# 判定不能、または圧縮ファイル等は汎用タイプへ
ctype = "application/octet-stream"
maintype, subtype = ctype.split("/", 1)
with open(path, "rb") as f:
file_data = f.read()
msg.add_attachment(
file_data,
maintype=maintype,
subtype=subtype,
filename=filename
)
print(f"追加: {filename}")
# 使用例
# msg = EmailMessage() ...
# attach_all_files_in_dir(msg, "./documents")
まとめ
EmailMessage クラスの add_attachment メソッドを使えば、複雑なMIME構造を意識せずにファイルを添付できます。
mimetypes モジュールと組み合わせることで、拡張子に応じた適切なファイル形式を自動設定し、スマートなメール送信プログラムを作成しましょう。
