Pythonを使って「任意のメールアドレスに自動でメールを送りたい」というニーズは非常に多くあります。
たとえば以下のような用途です。
- Raspberry Pi のセンサー異常をメール通知
- 定期バッチの完了通知
- Webアプリのアラート送信
- 個人ツールのログ送信
本記事では Yahooメールを使って Python から SMTP 送信する方法 を、初心者の方でも理解できるように解説します。
さらに、実際によく遭遇する次のエラーについても詳しく説明します。
TimeoutError: timed out
このエラーは「コードが間違っている」わけではないケースが非常に多いため、原因の切り分けと正しい対処法を知ることが重要です。
Pythonでメール送信する基本仕組み(超重要)
Pythonでメールを送る場合、以下の流れになります。
- SMTPサーバーに接続
- 暗号化(STARTTLS or SSL)
- ログイン
- メール送信
これを担当するのが 標準ライブラリ smtplib です。
YahooメールのSMTP設定
Yahooメールを使う場合、以下の設定が必要です。
| 項目 | 値 |
|---|---|
| SMTPサーバー | smtp.mail.yahoo.co.jp |
| ポート | 587(STARTTLS) |
| 代替ポート | 465(SSL) |
| ユーザー名 | Yahooメールアドレス |
| パスワード | アプリパスワード |
⚠️ 通常のログインパスワードは使用できません。
Yahooの「アプリパスワード」を必ず発行してください。
よくあるエラー:TimeoutError の正体
多くの初心者が以下のエラーで詰まります。
TimeoutError: timed out
これは何を意味している?
👉 SMTPサーバーに TCP 接続できていない
つまり、
- コード以前の問題
- ネットワーク的に遮断されている可能性が高い
ということです。
TimeoutErrorが出る主な原因(重要)
| 原因 | 説明 |
|---|---|
| 会社・学校の回線 | SMTP(587/465)がブロックされている |
| セキュリティソフト | メール通信を遮断 |
| ISP制限 | 一部プロバイダでSMTP制限 |
| Wi-Fiルータ | フィルタリング設定 |
| ポート指定ミス | 587/465以外を使用 |
コードを直しても解決しないケースが非常に多いのが特徴です。
まず確認すべきこと(Windows)
PowerShellで次を実行してください。
Test-NetConnection smtp.mail.yahoo.co.jp -Port 587
結果がこうなれば ネットワーク遮断です。
TcpTestSucceeded : False
この場合、以下を試してください。
- スマホのテザリングで接続
- 別のWi-Fi環境
- 465ポートを使用
初心者向け:587 → 465 自動切替コード(完成版)
以下は 587がダメでも465で再試行する安全な実装です。
.env ファイル
SMTP_HOST=smtp.mail.yahoo.co.jp
SMTP_USER=your_id@yahoo.co.jp
SMTP_PASS=アプリパスワード
MAIL_FROM=your_id@yahoo.co.jp
Pythonコード(コピペOK)
import os
import socket
import smtplib
from email.message import EmailMessage
from dotenv import load_dotenv
load_dotenv()
SMTP_HOST = os.getenv("SMTP_HOST")
SMTP_USER = os.getenv("SMTP_USER")
SMTP_PASS = os.getenv("SMTP_PASS")
MAIL_FROM = os.getenv("MAIL_FROM", SMTP_USER)
def send_mail(to_addr, subject, body):
msg = EmailMessage()
msg["From"] = MAIL_FROM
msg["To"] = to_addr
msg["Subject"] = subject
msg.set_content(body)
last_error = None
# 587 STARTTLS
try:
with smtplib.SMTP(SMTP_HOST, 587, timeout=20) as smtp:
smtp.ehlo()
smtp.starttls()
smtp.ehlo()
smtp.login(SMTP_USER, SMTP_PASS)
smtp.send_message(msg)
print("Send via 587 OK")
return
except Exception as e:
last_error = e
# 465 SSL
try:
with smtplib.SMTP_SSL(SMTP_HOST, 465, timeout=20) as smtp:
smtp.login(SMTP_USER, SMTP_PASS)
smtp.send_message(msg)
print("Send via 465 OK")
return
except Exception as e:
last_error = e
raise RuntimeError(f"SMTP送信失敗: {last_error}")
if __name__ == "__main__":
send_mail(
"destination@example.com",
"Python SMTPテスト",
"Yahooメールからのテスト送信です。"
)
それでもダメな場合の最短解決策
- スマホのテザリングで試す(最強)
- 社内PCなら個人回線で実行
- セキュリティソフトの「メール保護」を一時OFF
👉 これで通るなら コードは正しい という証明になります。
セキュリティ上の注意(重要)
- SMTPパスワードは 絶対にコードに直書きしない
.envは Git に入れない- ログ出力しない
これは 実務・製品レベルで必須 です。
まとめ
TimeoutErrorは ネットワーク遮断が原因- Yahoo SMTPは 587 / 465 の2択
- 465(SSL)が通る環境は多い
- コードより 回線チェックが重要
.env管理は必須
