WordPressからメールが届かない時の対処法(送信できているか確認)
実測 に検証
問い合わせフォームの通知が来ない。パスワード再設定のメールも来ない。
この症状は2 つの全く違う状態に分かれます。切り分けないまま SMTP プラグインを入れたり SPF を設定したりしても、原因が別なら直りません。
| 状態 | 意味 | 直す場所 |
|---|---|---|
wp_mail() が false を返している | WordPress が送信すらしていない | WordPress 側の設定 |
wp_mail() が true を返している | 送信はした。届いていないだけ | サーバー・DNS・受信側 |
先にどちらかを確定させます。
見分け方: 画面の文言で分かる
「パスワードをお忘れですか?」からリセットを要求すると、 WordPress が結果をそのまま画面に出します。実測した 2 つの状態です。
| 送信できていない | 送信できた | |
|---|---|---|
| POST 後の HTTP | 200 | 302 |
| 画面 | 「エラー: メールを送信できませんでした。サイトのメール送信が正しく設定されていない可能性があります。」 | 「確認のリンクを含むメールを送信しました」 |
| 実際の受信 | 0 通 | 1 通 |

送信できていない状態。WordPress がメールを送っていない

送信できた状態。ここから先で届かないなら WordPress の外の問題
「送信できませんでした」と出ているなら wp_mail() は false です。
この場合、SPF や DKIM をいくら設定しても意味がありません。
「送信しました」と出ているのに届かない場合は、WordPress 側は成功しています。 原因はサーバーの送信経路か、受信側の迷惑メール判定です。
wp_mail() が false になる代表的な原因: 送信元アドレス
WordPress の既定の送信元は wordpress@<サーバー名> です。
サーバー名にドットが含まれていないと、PHPMailer が不正なアドレスと判定して
送信を中止します。
実測したエラーです。
wp_mail_failed: 無効なアドレス: (From): wordpress@localhost
wp_mail: false
localhost やコンテナのホスト名のように、ドットのないホスト名の環境で起きます。
共用サーバーでは起きにくいですが、VPS・Docker・社内サーバーでは頻発します。
対処は送信元アドレスを明示的に差し替えることです。
add_filter( 'wp_mail_from', function () {
return 'no-reply@example.com'; // 実在するドメインにする
} );
add_filter( 'wp_mail_from_name', function () {
return 'サイト名';
} );
ドメインは実在するものにします。存在しないドメインを送信元にすると、
今度は受信側で弾かれます(wp_mail() は true を返すので、
症状が「届かないだけ」に変わってしまい、原因が見えにくくなります)。
エラーの中身を取る
wp_mail() は false しか返さないので、理由を取るには
wp_mail_failed フックを使います。原因の特定にはこれが最短です。
// mu-plugins に置く
add_action( 'wp_mail_failed', function ( $error ) {
error_log( '[wp_mail_failed] ' . $error->get_error_message() );
} );
wp-content/debug.log に理由が出ます。実測では
無効なアドレス: (From): wordpress@localhost が記録されました。
測り方を間違えると誤診する
これは検証中に自分が踏んだ落とし穴です。
WP-CLI から wp_mail() を呼んで確認したところ false が返りました。
しかし原因はまったく別でした。
sendmail: can't connect to remote host (127.0.0.1): Connection refused
wp_mail: false
WP-CLI は Web サーバーとは別の環境で動いていることがあります(この検証環境では 別コンテナ)。そちらに送信経路が設定されていなければ、当然 false になります。 Web 経由では同じ設定で正常に送信できていました。
つまり、メールの検証は実際の経路(Web からの操作)で行う必要があります。 コマンドラインでの結果をそのまま信じると、直っているものを壊しに行きます。
同じことは共用サーバーでも起きます。cron から動かしたときだけ送れない、 管理画面からは送れる、という差はこの層の違いです。
wp_mail() が true なのに届かない場合
WordPress は無罪です。見る場所は 3 つです。
1. 送信元ドメインが実在し、SPF が通っているか
no-reply@自分のドメイン にしておき、そのドメインの SPF レコードに
サーバーの送信元を含めます。サーバーの共有 IP が他利用者のせいで
ブロックされていることもあるため、これが疑わしいなら次へ進みます。
2. SMTP を使う
PHP の mail() 関数を使わず、外部の SMTP サービス経由に切り替えます。
送信の成否とログがサービス側に残るので、切り分けが一気に楽になります。
「届かない」を調べる作業が「送信ログを見る」作業に変わります。
3. 受信側の迷惑メール判定
Gmail 宛だけ届かない、などの偏りがあればこれです。 受信側の迷惑メールフォルダと、ドメインの DMARC を確認します。
フォームの通知が来ない場合の追加確認
問い合わせフォームに限っては、メール以前の問題であることがあります。
- 送信自体が失敗している(キャッシュに nonce が焼き込まれて期限切れ)
- 管理画面のフォーム設定で宛先が空・誤り
- スパム対策プラグインが送信を破棄している
まず「フォームの送信記録が残っているか」を確認します。 記録があるならメールの問題、無いなら送信の問題です。 記録を残す機能がないフォームプラグインなら、先に プラグインの競合 の観点で キャッシュとの組み合わせを確認します。
なお現行の Contact Form 7 では、未ログインの訪問者向けに nonce を出していないため、 nonce の期限切れは原因になりません。送信ボタンが止まる場合は → Contact Form 7 で送信できない
確認の順番
- 「パスワードをお忘れですか?」でリセットを要求する —
画面の文言で
wp_mail()の成否が分かる - 「送信できませんでした」 →
wp_mail_failedフックで理由をログに出す → 送信元アドレスを疑う - 「送信しました」なのに届かない → SPF / SMTP / 受信側
- 確認は必ず Web 経由で行う(コマンドラインの結果は別経路のもの)
再現手順
この検証環境では Mailpit(受信箱)を持っているので、 「WordPress は送ったのか」を確実に分離できます。
# 受信箱を空にする
curl -s -X DELETE "http://localhost:8025/api/v1/messages"
# パスワード再設定を要求(Web 経由)
curl -s -X POST "http://localhost:8080/wp-login.php?action=lostpassword" \
--data-urlencode "user_login=admin" --data "wp-submit=send" -o /tmp/lp.html -w '%{http_code}\n'
# 届いたか
curl -s "http://localhost:8025/api/v1/messages?limit=1"
# 送信元の修正を外すと再現する
mv src/wp-content/mu-plugins/lab-mail.php /tmp/
# → HTTP 200・受信 0 通・画面に「メールを送信できませんでした」
mv /tmp/lab-mail.php src/wp-content/mu-plugins/