【Python初心者】YahooメールでSMTP送信する方法|TimeoutErrorの原因と完全対処ガイド

Python

Pythonを使って「任意のメールアドレスに自動でメールを送りたい」というニーズは非常に多くあります。
たとえば以下のような用途です。

  • Raspberry Pi のセンサー異常をメール通知
  • 定期バッチの完了通知
  • Webアプリのアラート送信
  • 個人ツールのログ送信

本記事では Yahooメールを使って Python から SMTP 送信する方法 を、初心者の方でも理解できるように解説します。

さらに、実際によく遭遇する次のエラーについても詳しく説明します。

TimeoutError: timed out

このエラーは「コードが間違っている」わけではないケースが非常に多いため、原因の切り分けと正しい対処法を知ることが重要です。

この記事でわかること
  • Pythonでメール送信する基本構造
  • YahooメールのSMTP設定(587 / 465)
  • .env を使った安全な認証情報管理
  • TimeoutError が出る本当の理由
  • 587が通らない環境での対処法
スポンサーリンク
スポンサーリンク

Pythonでメール送信する基本仕組み(超重要)

Pythonでメールを送る場合、以下の流れになります。

  1. SMTPサーバーに接続
  2. 暗号化(STARTTLS or SSL)
  3. ログイン
  4. メール送信

これを担当するのが 標準ライブラリ 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 管理は必須
タイトルとURLをコピーしました