更新履歴(3件・最終更新 2026年08月02日)
この記事に加えた変更の記録です。アーカイブした更新前のバージョンは、DOI付きの固定URLから読めます。
- 記事の冒頭に「この記事の知識マップ」節を追加しました。本文で扱っている概念とその関係を、要約・図・詳細ページへのリンクにまとめたものです。本文の主張は変えていません。
- 外部レビュー(1283件)への対応として本文を更新しました。個々の変更内容は、この下の履歴を参照してください。
- エグゼクティブサマリーを結論3点に圧縮し、対象読者と前提環境の表、用語ミニ辞書、記事の構成を冒頭に追加しました。共有レンタルサーバーで契約先に確認すべき項目の表と、RFCおよびGmail送信者ガイドラインへの参考リンク節を新設しました。
- 初版公開
この記事を引用する(DOI: 10.5281/zenodo.21589804)
この記事はZenodoにアーカイブされています。常に最新版へ解決されるDOIと、いま表示している版に固定されたDOIの両方を下に示します。
小村 豪(2026)「問い合わせフォームのメールが届かない原因と直し方」合同会社小村ソフト. https://doi.org/10.5281/zenodo.21589804 https://staging.comcomponent.com/blog/2026/04/25/000-contact-form-email-delivery-troubleshooting/
- DOI(最新版)
- 10.5281/zenodo.21589804
- DOI(この版)
- 10.5281/zenodo.21732816
1. エグゼクティブサマリー
問い合わせフォームの通知メールが「送信は成功しているのに届かない」とき、原因はたいていメール送信のコードではなく、差出人の設計にあります。結論は3点です。
From:は自サイトのドメインに固定し、フォーム利用者のアドレスはReply-To:に入れる。 見えている差出人と、実際に認証されるドメインを揃えるためです。- SPF と DKIM を両方整える。 転送は SPF を壊しやすく、SPF だけに頼ると正当なメールでも落ちます。
- DMARC は
p=noneの観測から始め、quarantine/rejectへ段階的に上げる。 いきなりrejectにすると、自社の正規メールまで止まります。
理由と根拠は2章以降で扱います。いま起きている不達をまず切り分けたい場合は、4章の診断手順から読んでも構いません。
対象読者と前提環境
この記事は、自社サイトの問い合わせフォームからの通知メールが届かないという問題を抱えている方に向けたものです。
| 項目 | 内容 |
|---|---|
| 想定読者 | Web サイトの担当者、フォームを実装した開発者、社内のメール周りを見ている情報システム担当者 |
| 環境に依存しない部分 | 2章〜5章(差出人の考え方、失敗シナリオ、ヘッダの読み方、From 設計)。送信基盤が何であっても同じ話です |
| 環境を前提にする部分 | 6章の設定例。PHP と Linux 系の送信基盤(Postfix / Exim / OpenDKIM)、および SendGrid・SES・Mailgun を題材にしています |
| 扱わないこと | 個別の CMS やフォームプラグインの設定画面、Exchange Online / Microsoft 365 の組織内メールフロー、メールマーケティングの配信設計 |
DNS レコード(SPF / DKIM / DMARC)とヘッダ設計の話は、Web サーバーが Windows でも Linux でも、送信が自前 MTA でも外部サービスでも共通です。実装言語が違っても、読み替えるのは「どこでヘッダを組み立てるか」と「どこでエンベロープ送信者を指定するか」の2点だけです。
この記事で使う用語
本文に断りなく出てくる用語を先にまとめます。
| 用語 | 意味 |
|---|---|
| MTA(Mail Transfer Agent) | メールを配送するサーバソフト。Postfix や Exim のほか、SendGrid や SES のような送信サービスもこの役割を担います |
| MUA(Mail User Agent) | 利用者が使うメールソフト。Outlook や Gmail の画面など |
| エンベロープ | SMTP のやり取りで渡す配送用の差出人と宛先(MAIL FROM / RCPT TO)。本文側のヘッダ From: To: とは別物で、封筒と便箋の関係にあたります |
| アラインメント | DMARC の判定で、From: ヘッダのドメインと、SPF や DKIM で認証されたドメインが揃っていること |
| レピュテーション | 送信元 IP や送信ドメインに対する受信側の評価。悪化すると迷惑メール判定や拒否につながります |
| PTR | IP アドレスからホスト名を引く、逆引き用の DNS レコード |
| DSN(Delivery Status Notification) | 配送結果の通知。いわゆるバウンスメールの機械可読な形式で、RFC 3464 が定義しています |
| milter | MTA にフィルタ処理を差し込む仕組み。DKIM 署名を付ける OpenDKIM もこの仕組みで動きます |
この記事の構成
- エグゼクティブサマリー(この章)
- SPF・DKIM・DMARC と From ヘッダの役割 ── 仕組みの理解
- 問い合わせフォームで起こりやすい失敗シナリオ
- 診断手順とコマンド ── ヘッダ、DNS、SMTP、実送信
- 推奨する From 設計パターン
- 構成別設定ガイド(外部 SMTP / 共有ホスティング / PHP)
- トラブルシューティングチェックリスト
この記事の知識マップ
この記事は、問い合わせフォームの通知メールが届かない主な原因は送信コードではなくFromヘッダの設計にあり、見える差出人と認証されるドメインをそろえることがDMARCのアラインメントを左右すると整理します。SPFはエンベロープ送信者(Return-Path)を、DKIMは署名ドメインを検証し、DMARCはその結果とFrom:ドメインの一致を判定するため、利用者アドレスをそのままFromに使う設計やメール転送によるSPFの破損はDMARC失敗の典型的な原因になります。共有ホスティングのローカルMTAやPHPのmail()、SendGrid・SES・Mailgunといった外部SMTPサービスではDKIMセレクタやPTR、カスタムMAIL FROMの設定が到達率を左右し、Reply-Toで返信先を確保しつつFromは自ドメインに固定する設計が推奨されるとしています。
flowchart LR
accTitle: 問い合わせフォームのメール到達性の知識マップ
accDescr: Fromヘッダの設計がSPF・DKIM・DMARCのアラインメントを通じてメールの到達性を左右し、転送や共有ホスティング、送信サービスの設定とどうつながるかを示す図です。
contact_form_notification_email["問い合わせフォームの通知メール"]
dmarc_alignment["DMARCのアラインメント"]
from_header["Fromヘッダ"]
reply_to_header["Reply-Toヘッダ"]
dmarc["DMARC"]
spf["SPF(Sender Policy Framework)"]
dkim["DKIM(DomainKeys Identified Mail)"]
unaligned_from_design["利用者アドレスをFromに使う設計"]
dmarc_failure["DMARCの失敗(dmarc=fail)"]
mail_forwarding_spf_failure["メール転送によるSPF失敗"]
return_path["Return-Path(エンベロープ送信者)"]
php_mail_function["PHPのmail()関数"]
header_injection["メールヘッダインジェクション"]
shared_hosting_mta["共有ホスティングのローカルMTA"]
ptr_record["PTRレコード(逆引き)"]
sendgrid_domain_authentication["SendGridのDomain Authentication"]
dkim_selector["DKIMセレクタ"]
ses_custom_mail_from["Amazon SESのカスタムMAIL FROM"]
mailgun_domain_verification["Mailgunの送信ドメイン検証"]
dmarc_policy_mode["DMARCポリシーモード"]
authentication_results_header["Authentication-Resultsヘッダ"]
sender_header["Senderヘッダ"]
from_header -->|"推奨される対応"| contact_form_notification_email
reply_to_header -->|"推奨される対応"| contact_form_notification_email
dmarc_alignment -->|"前提とする"| from_header
dmarc -->|"利用する"| spf
dmarc -->|"利用する"| dkim
dmarc -->|"前提とする"| dmarc_alignment
unaligned_from_design -->|"原因になり得る"| dmarc_failure
mail_forwarding_spf_failure -.->|"原因になり得る"| dmarc_failure
dkim -->|"軽減する"| dmarc_failure
spf -->|"利用する"| return_path
return_path -.->|"で構成できる"| php_mail_function
php_mail_function -.->|"原因になり得る"| header_injection
shared_hosting_mta -.->|"原因になり得る"| dmarc_failure
ptr_record -->|"推奨される対応"| shared_hosting_mta
sendgrid_domain_authentication -->|"前提とする"| dkim_selector
ses_custom_mail_from -->|"前提とする"| return_path
mailgun_domain_verification -->|"前提とする"| dkim_selector
dmarc -->|"で構成できる"| dmarc_policy_mode
dmarc_alignment -->|"で確認できる"| authentication_results_header
sender_header -->|"用いるのは非推奨"| contact_form_notification_email
unaligned_from_design -->|"用いるのは非推奨"| contact_form_notification_email
dkim -->|"で構成できる"| dkim_selector
図の実線は常に成り立つ関係、破線は条件付きの関係です(成立条件は詳細ページの各関係の説明に記載)。関係すべての一覧(全22件、根拠・確度つき)と主要概念の定義は知識マップ詳細ページにまとめています。データ: JSON-LD / Turtle
2. SPF・DKIM・DMARC と From ヘッダの役割
メール配送では、エンベロープとヘッダを分けて考える必要があります。SPF が主に検証するのは SMTP セッション中の MAIL FROM で、これは配送上の差出人です。最終配送時には、その逆経路が Return-Path として 1 つだけ残されるべきで、送信側 SMTP システムは最初から Return-Path ヘッダを持ったメッセージを作るべきではありません。いっぽう From: は本文ヘッダ側の「誰からのメールに見えるか」を表し、Reply-To: は返信先、Sender: は実際に送出した主体を表します。
RFC 5322 は、From: をメッセージの作者、Sender: を実送信主体として定義しています。作者と送信主体が同じなら Sender: は使うべきではなく、返信先を作者とは別にしたいときは Reply-To: を使うのが正しい筋です。さらに RFC 5322 は、From: に作者のものでないアドレスを入れるべきではない、と明記しています。問い合わせフォーム通知は通常、ユーザー本人が MUA から送っているのではなく、サイト側システムが作る通知なので、利用者アドレスを From: に置く設計は仕様の意味ともズレやすいです。
DKIM は、メッセージの一部ヘッダと本文に対して署名を付け、受信側が DNS にある公開鍵で検証します。署名ドメインは DKIM-Signature の d= で表され、公開鍵は selector._domainkey.example.com のようにセレクタで引きます。DKIM は「転送でも比較的生き残りやすい」認証として使われますが、本文や署名対象ヘッダが途中で改変されると、bh= の本文ハッシュや署名検証が失敗します。
DMARC は、SPF や DKIM の成否だけではなく、それらの認証済みドメインが From: ドメインと整合しているかを見ます。ここがポイントです。SPF が通っても MAIL FROM=bounces.vendor.net で From: contact@example.com なら、SPF のアラインメントは落ちます。DKIM が d=example.com で通っていれば DMARC はパスできますが、DKIM も無いと DMARC 失敗です。DMARC には adkim / aspf による strict / relaxed のアラインメントモード、p=none|quarantine|reject のポリシー、rua / ruf のレポート送信先が定義されています。
Gmail の最近のガイドラインは、この設計思想をそのまま運用要件に落とし込んでいます。Google は「From: ヘッダのなりすましをしないこと」「ダイレクトメールでは From: ヘッダ内ドメインが SPF ドメインまたは DKIM ドメインと一致していること」を明示しています。問い合わせフォーム通知はマーケティングメールではありませんが、受信側フィルタの基本ロジックは同じなので、この考え方を無視すると到達率は下がります。
sequenceDiagram
participant User as フォーム利用者
participant App as Webアプリ
participant SMTP as 送信MTA / SMTPサービス
participant DNS as DNS
participant MX as 受信側MX
User->>App: フォーム送信
App->>App: From / Reply-To / Sender を決定
App->>SMTP: SMTP送信要求
SMTP->>SMTP: DKIM署名付与
SMTP->>MX: MAIL FROM / RCPT TO / DATA
MX->>DNS: SPF参照(MAIL FROM)
MX->>DNS: DKIM公開鍵参照(selector._domainkey)
MX->>DNS: DMARC参照(_dmarc + Fromドメイン)
MX->>MX: Alignment判定
MX-->>App: 受信・迷惑メール・拒否・バウンス
このフローで重要なのは、DMARC の判定基準が最後まで From: ドメイン中心だという点です。アプリ側で From:、SMTP 側で MAIL FROM、DNS 側で SPF/DKIM/DMARC を別々に触るため、どれか 1 つだけ直しても不達は解決しません。
3. 問い合わせフォームで起こりやすい失敗シナリオ
もっとも多いのは、フォーム利用者のアドレスを From: に入れてしまうケースです。たとえばサイトの SMTP から送るのに From: taro@gmail.com とすると、SPF や DKIM が通るのは普通はサイト側ドメインであって Gmail 側ドメインではありません。その結果、From: は Gmail、認証済みドメインは example.com というズレが起き、DMARC アラインメントに失敗します。Google 自身も From: のなりすまし回避と、From: と SPF/DKIM ドメインの一致を求めています。
次に多いのは、転送で SPF が壊れるケースです。メール転送では、最終受信者から見た送信元 IP が「元の送信ドメインの SPF に載っていない中継サーバ」になりやすいため、正当なメールでも SPF が落ちます。Google も「転送されたメールは SPF に失敗しやすいので DKIM を必ず使うべき」と案内しています。さらに、中継先が本文や件名プレフィックス、フッタ追加などを行うと DKIM まで壊れます。
外部 SMTP サービス利用時の初期設定不足も典型です。SendGrid では Domain Authentication を設定しないと送信できないケースがあり、Automated Security を ON にすると CNAME ベースで認証レコードが生成され、必要に応じて Custom Return Path や Custom DKIM Selector を設定できます。SES ではデフォルトで amazonses.com の MAIL FROM が使われ、SPF は暗黙的に成立しますが、サイトドメインとの SPF アラインメントを取りたいならカスタム MAIL FROM を設定する必要があります。Mailgun でも送信ドメインの SPF/DKIM と必要な MX が未設定だと、正しい送信署名が成立しません。
共有ホスティングのローカル MTA は、見落としやすい地雷です。自サイトが認証済みでも、実際に外へ出ていく IP が共有 IP でレピュテーションが悪い、PTR が無い、あるいはホスティング側で DKIM が載っていないと、到達率が落ちます。Google は送信元 IP の PTR を要件化しており、共有 IP の評判が悪いと 5.7.1 系エラーの原因にもなると案内しています。
PHP の mail() や送信ライブラリの使い方も失敗しやすいです。PHP マニュアルは mail() に From ヘッダが必要であること、追加パラメータで sendmail -f によるエンベロープ送信者指定ができることを説明しています。つまり、Return-Path: ヘッダを自分で組み立てるのではなく、エンベロープ送信者を MTA に渡すのが筋です。ここを誤解すると、SPF 判定に使われる送信者と、アプリが想定している送信者がズレます。
最後に、Reply-To を使うべき場面で Sender や From をいじってしまうケースがあります。返信先を利用者に向けたいだけなら Reply-To で十分です。Sender は「作者と実送信主体が異なる」ことを明示したいときに使うヘッダで、問い合わせフォームで常用するものではありません。設計の目的が「返信を利用者へ返したい」なのか、「通知の責任主体を示したい」なのかを分けて考えると、事故が減ります。
4. 診断手順とコマンド
まずやるべきことは、コードを見る前に、生のメールヘッダを見ることです。Gmail では「メッセージのソースを表示」、Outlook では「メッセージの詳細」または「インターネット ヘッダー」から、Authentication-Results、Return-Path、From、Reply-To、DKIM-Signature、Received を確認できます。ここを見れば、問題が「送れていない」のか「認証と整合性が崩れている」のかをかなりの精度で切り分けられます。
ヘッダで最初に見るポイント
最優先はこの 5 点です。
From:のドメインは何かReturn-Path:のドメインは何かAuthentication-Results:でspf=pass/dkim=pass/dmarc=passが出ているかdkim=passのときheader.i=またはd=がどのドメインかdmarc=failのとき、理由が 認証失敗なのか alignment failure なのか
Google の DMARC トラブルシュートにも、メッセージが他の認証には通っていても、ヘッダがアラインしていなければ DMARC に失敗すると明記されています。
DNS を確認するコマンド
dig は DNS トラブルシュート向けの定番ツールで、BIND のマニュアルでも柔軟で明快な出力を持つ DNS 参照ツールと説明されています。nslookup は非対話モードでも使える、より軽い確認用コマンドです。問い合わせフォームの認証確認では、最低でも SPF、DKIM、DMARC の 3 つを引きます。
# SPF
dig +short TXT example.com
# DKIM
dig +short TXT form2026._domainkey.example.com
# DMARC
dig +short TXT _dmarc.example.com
# Windows なら
nslookup -type=txt example.com
nslookup -type=txt _dmarc.example.com
nslookup -type=txt form2026._domainkey.example.com
想定される出力例は次のような形です。
"v=spf1 include:sendgrid.net include:mailgun.org ip4:203.0.113.10 -all"
"v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQ..."
"v=DMARC1; p=none; rua=mailto:dmarc-agg@example.com; ruf=mailto:dmarc-afrf@example.com; adkim=r; aspf=r; fo=1"
ここで見るべきなのは、SPF レコードが 1 つにまとまっているか、DKIM の公開鍵が引けるか、DMARC に p= があるかです。SPF は DNS 参照を発生させるメカニズムを合計 10 個までに制限すべきと RFC 7208 が定めており、超えると permerror の原因になります。
SMTP 接続と TLS の確認
openssl s_client は OpenSSL の汎用 SSL/TLS クライアントで、SMTP サーバの STARTTLS や証明書チェーン確認に便利です。-starttls smtp で SMTP の STARTTLS を開始し、-showcerts でサーバが返した証明書一覧を確認できます。
printf 'QUIT\r\n' | openssl s_client \
-connect smtp.example.com:587 \
-starttls smtp \
-servername smtp.example.com \
-showcerts \
-brief
出力例です。
CONNECTION ESTABLISHED
Protocol version: TLSv1.3
Ciphersuite: TLS_AES_256_GCM_SHA384
Verification: OK
250 CHUNKING
これで少なくとも、SMTP サーバに接続できるか、STARTTLS が有効か、証明書検証で明らかな異常がないかを見られます。Google は一定規模以上の送信者に TLS を求めており、TLS 未使用は 5.7.29 の原因になり得ます。
実送信の再現テスト
swaks は SMTP テスト専用の実践ツールで、TLS、認証、SMTP 拡張を含む送信テストを柔軟に再現できます。問い合わせフォームの不達調査では、「アプリを通さず、同じ SMTP / 同じ From / 同じ Reply-To / 同じ宛先で」1 通だけ送って再現するのが有効です。
swaks \
--server smtp.example.com \
--port 587 \
--tls \
--auth LOGIN \
--auth-user contact@example.com \
--auth-password '********' \
--from bounce@example.com \
--to yourtest@gmail.com \
--h-From "サイト通知 <contact@example.com>" \
--h-Reply-To "山田太郎 <visitor@gmail.com>" \
--header "Subject: swaks test" \
--body "This is a test"
送信成功時の典型はこうです。
=== Trying smtp.example.com:587...
=== Connected to smtp.example.com.
<- 250-STARTTLS
<- 250-AUTH LOGIN PLAIN
-> STARTTLS
<- 220 Ready to start TLS
...
<- 250 2.0.0 Ok: queued as ABC123DEF
アプリ経由では失敗し、swaks では通るなら、原因はライブラリのヘッダ組み立てかエンベロープ送信者設定に寄っている可能性が高いです。逆に swaks でも同じように落ちるなら、DNS・SMTP・受信側ポリシーの問題に絞れます。
mail-tester で外形診断する
mail-tester は、ランダムなテスト用アドレスにメールを送らせ、そのメッセージ、送信サーバ、送信 IP を解析して詳細レポートを返すサービスです。ローカル MTA や共用サーバで「何となく届かない」ケースの一次診断に向いています。
使い方は単純です。
- mail-tester で発行されたテストアドレスを取得する
- 問い合わせフォームと同じ経路で 1 通送る
- スコアと、SPF / DKIM / DMARC / 逆引き / ブラックリスト / 本文構成の指摘を見る
mail-tester のスコアだけで本番配信を判断してはいけませんが、少なくとも「SPF がそもそも見えていない」「DKIM 公開鍵が引けない」「本文や差出人構成が不自然」などは早く見つかります。
ヘッダ解析のサンプル
失敗例です。
Return-Path: <bounce-123@vendor.example.net>
Authentication-Results: mx.google.com;
spf=pass (google.com: domain of bounce-123@vendor.example.net designates 198.51.100.10 as permitted sender) smtp.mailfrom=vendor.example.net;
dkim=none;
dmarc=fail (p=quarantine sp=quarantine dis=none) header.from=gmail.com
From: 山田太郎 <visitor@gmail.com>
Reply-To: 山田太郎 <visitor@gmail.com>
Subject: お問い合わせ
このメールは SPF 自体は通っていても、From: が gmail.com なので DMARC は失敗です。問い合わせフォームで利用者アドレスを From: に入れた典型的な壊れ方です。
成功例はこうです。
Return-Path: <bounce@example.com>
Authentication-Results: mx.google.com;
spf=pass smtp.mailfrom=example.com;
dkim=pass header.i=@example.com header.s=form2026;
dmarc=pass header.from=example.com
From: Example Site <contact@example.com>
Reply-To: 山田太郎 <visitor@gmail.com>
Subject: お問い合わせ通知
この形なら、利用者への返信しやすさは Reply-To: で確保しつつ、見える差出人も認証済み差出人も example.com で揃うため、到達率は大きく安定します。
5. 推奨する From 設計パターン
問い合わせフォームでぶれない原則は、「認証に使うドメイン」と「受信者に見せる From ドメイン」を揃えることです。そのうえで、返信先だけを Reply-To: に逃がします。Sender: は必要な場合だけ、Return-Path はエンベロープで設定する、という三層構造に分けると設計が安定します。
| パターン | ヘッダ例 | 向いているケース | 長所 | 注意点 |
|---|---|---|---|---|
| 推奨パターン | From: contact@example.comReply-To: visitor@gmail.comReturn-Path: bounce@example.com |
ほぼすべての問い合わせフォーム | DMARC を取りやすい/返信しやすい/実装が単純 | Reply-To を忘れると返信先がサイト側になる |
| サブドメイン分離 | From: contact@form.example.comReply-To: visitor@gmail.comReturn-Path: bounce.form.example.com |
フォーム通知を本体メールと分離したい | レピュテーション分離しやすい/管理しやすい | SPF/DKIM/DMARC をサブドメイン側でも整える必要がある |
Sender 明示型 |
From: contact@example.comSender: mailer@example.comReply-To: visitor@gmail.com |
送信主体を明示したい特殊要件 | 運用責任主体を見せられる | 通常は不要。作者と送信主体が同じなら冗長 |
| 非推奨パターン | From: visitor@gmail.comReply-To: visitor@gmail.com |
返信先を目立たせたいだけの実装 | 見た目だけは自然 | DMARC 失敗の原因になりやすい。問い合わせ通知では避けるべき |
この表の根拠は RFC 5322 の From / Sender / Reply-To の意味づけと、RFC 5321 の Return-Path の扱い、そして DMARC が From: 基準で整合性を判定するという仕様です。フォーム通知のデフォルトは 1 行目の「推奨パターン」 で十分です。From: に利用者アドレスを置きたくなる場面でも、返信先を Reply-To: に入れれば目的は達成できます。
特に覚えておきたいのは、Return-Path は「編集するヘッダ」ではなく「配送で使うエンベロープ送信者の結果」だということです。PHP mail() なら -f、SMTP サービスなら Custom MAIL FROM / Return Path / bounce domain のような設定項目で扱うのが正しい実装です。
6. 構成別設定ガイド
ここからは、現場で多い 3 パターンごとに設定の考え方を整理します。前提として、DNS に入れる正確な値は各サービスの管理画面が出す値を優先してください。以下のレコード例は、構造を理解するための代表例です。
サイトが外部 SMTP を使う場合
外部 SMTP の最重要ポイントは、自ドメインの認証を先に済ませることです。Google も、メールサービスプロバイダを使う場合は、そのサービスが自ドメインの SPF と DKIM を認証していることを確認するよう案内しています。
推奨構成
From:はcontact@example.comまたはcontact@form.example.comReply-To:はフォーム利用者アドレスReturn-Path/ MAIL FROM はbounce.example.comなど自分が管理するバウンス用サブドメイン- DKIM は
example.comまたは送信用サブドメインで署名 - DMARC は 見える
From:ドメイン に置く
SendGrid の典型設定
SendGrid では Domain Authentication が前提で、Automated Security を ON にすると 3 つの CNAME が生成されます。OFF の場合は 1 つの MX と 2 つの TXT が生成され、Custom Return Path や Custom DKIM Selector も設定できます。
; 例: SendGrid(実際の値は管理画面で生成されたものを使う)
em123.example.com. CNAME u123456.wl.sendgrid.net.
s1._domainkey.example.com. CNAME s1.domainkey.u123456.wl.sendgrid.net.
s2._domainkey.example.com. CNAME s2.domainkey.u123456.wl.sendgrid.net.
_dmarc.example.com. TXT "v=DMARC1; p=none; rua=mailto:dmarc-agg@example.com"
SendGrid でハマりやすいのは、「SMTP 認証だけ済ませて、ドメイン認証は未設定」の状態です。この状態だと送信自体はできても、受信側から見ると From: と認証済みドメインの関係が弱くなります。Domain Authentication を通し、その上で Custom Return Path を必要に応じて設定するのが基本です。
SES の典型設定
SES はデフォルトで amazonses.com サブドメインの MAIL FROM を使うため、SPF 自体は暗黙的に成立します。ただし、サイトドメインと SPF アラインメントを取りたいなら、カスタム MAIL FROM を使います。このとき SES は、カスタム MAIL FROM ドメインに SPF TXT と MX を要求し、MX はちょうど 1 つでなければいけません。また Easy DKIM では 3 つの CNAME を DNS に追加します。
; 例: SES Easy DKIM
abcde12345._domainkey.example.com. CNAME abcde12345.dkim.amazonses.com.
fghij67890._domainkey.example.com. CNAME fghij67890.dkim.amazonses.com.
klmno54321._domainkey.example.com. CNAME klmno54321.dkim.amazonses.com.
; 例: SES custom MAIL FROM
bounce.example.com. MX 10 feedback-smtp.ap-northeast-1.amazonses.com.
bounce.example.com. TXT "v=spf1 include:amazonses.com -all"
_dmarc.example.com. TXT "v=DMARC1; p=none; rua=mailto:dmarc-agg@example.com"
SES の設計で重要なのは、MAIL FROM 用ドメインは送信用 From: ドメインそのものではなく、バウンス専用のサブドメインにすることです。AWS も MAIL FROM は、実際にメールを送るドメインそのものではないサブドメインにするよう案内しています。
Mailgun の典型設定
Mailgun では送信ドメイン検証時に、SPF 用 TXT と DKIM 用 TXT が必要で、さらに 2 つの MX を追加します。既に SPF がある場合は、新しい SPF レコードを増やすのではなく、既存レコードに include:mailgun.org を差し込みます。DKIM キーは複数見える場合がありますが、現在使うキーが DNS に正しく載っていれば送信は可能です。
; 例: Mailgun をサブドメインで使う
mg.example.com. TXT "v=spf1 include:mailgun.org ~all"
mx._domainkey.mg.example.com. TXT "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQ..."
mg.example.com. MX 10 mxa.mailgun.org.
mg.example.com. MX 10 mxb.mailgun.org.
email.mg.example.com. CNAME mailgun.org.
_dmarc.example.com. TXT "v=DMARC1; p=none; rua=mailto:dmarc-agg@example.com"
Mailgun はサブドメイン運用と相性が良いので、mg.example.com のような専用送信サブドメインを切ると、フォーム通知やトランザクション通知の管理がしやすくなります。
サイトが共有ホスティングのローカル MTA で送る場合
共有ホスティングでまず見るべきは、自分のアプリではなくホスティング側の送信基盤品質です。送信 IP の PTR、DKIM 対応、共有 IP の評判、送信ログの見え方が弱い場合、この構成はそれだけで不利です。Google も送信 IP の PTR を重視しており、共有 IP の評判が悪い場合にはブロック原因になり得ると案内しています。
実務的には、この順で進めるのが安全です。
- ホスティング会社が SPF/DKIM/PTR を管理画面またはサポートで設定可能か確認する
From:は必ず自ドメインに固定する- SPF にホスティングの送信元 IP または許可された送信ドメインを含める
- DKIM をホスティング機能で有効化する。無ければ外部 SMTP へ切り替える
- 可能なら MAIL FROM 用のバウンスアドレスを
bounce.example.comのように分ける
共有レンタルサーバーでは、まず契約先に確認する
共有レンタルサーバーでは、送信基盤を自分で触れる範囲が限られます。手を動かす前に、管理画面・マニュアル・サポート窓口で次を確認してください。
| 確認すること | 確認できない・できないときの意味 |
|---|---|
| 送信メールに自ドメインで DKIM 署名を付ける機能があるか | DKIM がないと、転送で SPF が落ちた時点で DMARC も落ちます |
| SPF レコードを自分で編集できるか(DNS を別会社で管理している場合も含む) | 送信元を SPF に追加できず、spf=fail を直せません |
| 送信に使われる IP と、その PTR(逆引き)がどうなっているか | 逆引き不備は、受信側で拒否理由になります |
| 共有 IP か専用 IP か | 共有 IP は、同居している他利用者の送信品質の影響を受けます |
| メール配送ログを参照できるか | 「送れたのか、拒否されたのか」を切り分けられません |
エンベロープ送信者(-f 相当)を指定できるか |
バウンス先と SPF 判定に使われる差出人を制御できません |
このうち DKIM 署名の可否 と 配送ログの可否 が、「この環境で調査と改善ができるか」の分かれ目です。どちらも「できない」なら、フォーム通知だけを外部 SMTP へ寄せるのが早道になります。フォーム通知は送信量が少なく、切り替えの影響範囲も限定的なので、最初の移行対象として扱いやすい部類です。
共有ホスティングで自分で DKIM を作る場合の典型例として、OpenDKIM 系では opendkim-genkey で 秘密鍵と DNS 用 TXT レコードを生成できます。DKIM の公開鍵はセレクタ付きの selector._domainkey.example.com に置く、という構造は RFC 6376 と一致しています。
mkdir -p /etc/opendkim/keys/example.com
opendkim-genkey -D /etc/opendkim/keys/example.com -d example.com -s form2026
chown opendkim:opendkim /etc/opendkim/keys/example.com/form2026.private
chmod 600 /etc/opendkim/keys/example.com/form2026.private
生成後のイメージはこうです。
form2026._domainkey.example.com. TXT "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQ..."
# /etc/opendkim/KeyTable
form2026._domainkey.example.com example.com:form2026:/etc/opendkim/keys/example.com/form2026.private
# /etc/opendkim/SigningTable
*@example.com form2026._domainkey.example.com
ただし、共有ホスティングで PTR や outbound relay を自分で制御できないなら、外部 SMTP に移す方が近道です。問い合わせフォーム通知のような少量送信でも、認証が弱いローカル MTA は Gmail や企業メールに不利です。
サイトが PHP mail() または SMTP ライブラリを使う場合
PHP mail() は便利ですが、認証と到達率の観点では「その先の MTA が何者か」に依存します。PHP マニュアルは、メールには From ヘッダが必要で、sendmail_path 経由の送信では追加パラメータでエンベロープ送信者を指定できる、と説明しています。逆にいえば、mail() を使っても SPF/DKIM/DMARC が自動で整うわけではありません。
まずは最低限、こう設計します。
From:はcontact@example.comReply-To:はフォーム利用者- エンベロープ送信者は
bounce@example.com - 本文には利用者のアドレスも明記する
- 可能なら
mail()ではなく、認証済み SMTP を使う
mail() の最小構成例
ヘッダに利用者入力をそのまま入れるのは危険です。$name や $email に CR/LF が混ざると、攻撃者が Bcc: などの追加ヘッダを差し込めてしまい、フォームがスパム中継器になります。PHP マニュアルもヘッダで使う外部入力は 必ず検証/正規化 するよう案内しています。下記の例では、エンベロープ送信者引数 (additional_params) を含め、ヘッダに混入させる値は事前にサニタイズします。
<?php
// ヘッダに使ってよい値だけを返す。CR/LF/NUL を含むなら拒否する。
function sanitize_header_value(string $value): string {
if (preg_match('/[\r\n\0]/', $value)) {
throw new InvalidArgumentException('Invalid characters in header value');
}
return trim($value);
}
// メールアドレスを RFC 準拠で検証する。
function sanitize_email(string $email): string {
$clean = sanitize_header_value($email);
if (!filter_var($clean, FILTER_VALIDATE_EMAIL)) {
throw new InvalidArgumentException('Invalid email address');
}
return $clean;
}
$to = 'ops@example.com';
$subject = sanitize_header_value('お問い合わせ通知');
// $name / $email / $message はフォーム入力。$message は本文用なので CR/LF を許容する一方、
// ヘッダで使う $name / $email は CR/LF を必ず弾く。
$safeName = sanitize_header_value($name);
$safeEmail = sanitize_email($email);
$body = <<<TEXT
Name: {$safeName}
Email: {$safeEmail}
{$message}
TEXT;
$headers = [
'From' => 'Example Site <contact@example.com>',
'Reply-To' => sprintf('%s <%s>', $safeName, $safeEmail),
'Content-Type' => 'text/plain; charset=UTF-8',
];
// additional_params もシェルに渡るため、固定値だけを使い動的入力は混ぜない。
mail($to, $subject, $body, $headers, '-fbounce@example.com');
この例のポイントは二つです。一つは、Return-Path: をヘッダとして書かず、5 番目の引数の -f でエンベロープ送信者を渡していること。もう一つは、Reply-To: 等のヘッダに混入させる利用者入力を、CR/LF を弾くサニタイズ関数を通していることです。サニタイズなしでヘッダを組み立てると、攻撃者が \r\nBcc: victim@example.com のような文字列を流し込んで追加ヘッダを差し込めるため、PHP マニュアルでも外部入力をヘッダに使うときの検証は必須とされています。additional_params も最終的にシェルに渡るため、利用者入力を混ぜず固定値で渡してください。
SMTP ライブラリを使う例
<?php
$mail->isSMTP();
$mail->Host = 'smtp.example.com';
$mail->Port = 587;
$mail->SMTPAuth = true;
$mail->SMTPSecure = 'tls';
$mail->Username = getenv('SMTP_USER');
$mail->Password = getenv('SMTP_PASS');
$mail->setFrom('contact@example.com', 'Example Site');
$mail->addAddress('ops@example.com');
$mail->addReplyTo($email, $name);
// ライブラリによっては Sender / return-path を別設定できる
$mail->Sender = 'bounce@example.com';
$mail->Subject = 'お問い合わせ通知';
$mail->Body = $body;
$mail->send();
SMTP ライブラリの利点は、ヘッダ差出人とエンベロープ差出人を分けて制御しやすいことです。問い合わせフォーム用途では、From: をサイトのドメインに固定し、返信先だけを Reply-To: に置く設計に最も向いています。
SPF・DKIM・DMARC の具体例
SPF の基本例
example.com. TXT "v=spf1 ip4:203.0.113.10 include:sendgrid.net -all"
SPF では、実際に送る送信元をすべて含める必要があります。サードパーティ送信者を使う場合、Google もその送信者を SPF と DKIM で認証しているか確認するよう求めています。なお SPF は DNS 参照回数に制限があるため、include の積みすぎにも注意が必要です。
DKIM の基本例
form2026._domainkey.example.com. TXT "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQ..."
セレクタは鍵ローテーションのために使われ、複数の公開鍵を同じドメインに共存させられます。運用では default より、用途や年月で区別できる名前にすると後で見やすいです。
DMARC の導入例
まずは観測モードです。
_dmarc.example.com. TXT "v=DMARC1; p=none; rua=mailto:dmarc-agg@example.com; ruf=mailto:dmarc-afrf@example.com; adkim=r; aspf=r; fo=1"
次に、一部を隔離したいときです。
_dmarc.example.com. TXT "v=DMARC1; p=quarantine; pct=25; rua=mailto:dmarc-agg@example.com; adkim=r; aspf=r"
最後に、厳格運用です。
_dmarc.example.com. TXT "v=DMARC1; p=reject; sp=reject; rua=mailto:dmarc-agg@example.com; adkim=s; aspf=s"
p=none は監視のみ、quarantine は隔離推奨、reject は SMTP 中の拒否推奨という意味です。adkim と aspf は strict/relaxed を切り替えます。いきなり reject へ行くより、none で流量と正規送信源を観測してから段階的に上げる方が安全です。
さらに rua / ruf を社外の集約サービスに送る場合、RFC 7489 では第三者側に追加の DNS レコードが必要です。たとえば example.com のレポートを thirdparty.example.net に送るなら、受信側は example.com._report._dmarc.thirdparty.example.net TXT "v=DMARC1" を公開する必要があります。
7. トラブルシューティングチェックリスト
最後に、現場でそのまま使える確認順をまとめます。問い合わせフォームのメール不達は、上から順に潰していくのが早道です。
まず確認すること
From:は自ドメインかReply-To:に利用者アドレスを入れているかAuthentication-Resultsでspf=passまたはdkim=passがあり、さらにdmarc=passかdmarc=failなら、認証失敗か alignment failure か- SPF が 1 レコードにまとまっているか
- SPF の参照回数が多すぎないか
- DKIM 公開鍵が引けるか
- DMARC に
p=があるか - 送信元 IP の PTR と逆引きが妥当か
- 共有 IP を使っていないか、またはレピュテーションが悪化していないか
バウンスとログで見る場所
バウンスメールが来ているなら、message/delivery-status 形式の DSN の中にある Final-Recipient、Status、Action、Diagnostic-Code が重要です。RFC 3464 は、こうした機械可読な配送失敗情報を定義しています。たとえば Diagnostic-Code: smtp; 550 relay not permitted のような行があれば、アプリ層ではなく SMTP 側の拒否です。
サーバ側では、少なくとも MTA の配送ログを見ます。Postfix なら配送成功・失敗、キュー滞留、リレー拒否、DNS 解決失敗、DKIM milter の警告が出ます。Exim でも同様です。代表的な確認コマンドを挙げておきます。
# 例: Postfix
journalctl -u postfix -n 200 --no-pager
postqueue -p
# 例: Exim
exim -bp
ホスティングによってはログパスやコマンド権限が違うため、「アプリのログ」ではなく「メール配送のログ」を見られるかどうかを先に確認してください。ここが見えない環境では、外部 SMTP へ寄せた方が問題解析しやすくなります。
Gmail と Outlook の見方
Gmail では「メッセージのソースを表示」、Microsoft の Outlook では「メッセージの詳細」や「インターネット ヘッダー」から、生ヘッダを確認できます。問い合わせフォーム不達の調査では、スクリーンショットよりヘッダ全文のテキストを保存して比較するのが有効です。
受信側エラーの見分け方
Gmail 系エラーは、コードから原因を読み取りやすいです。
| エラー例 | 意味 | 主な対処 |
|---|---|---|
5.7.27 |
SPF 不合格 | SPF レコードに送信元を追加 |
5.7.30 |
DKIM 不合格 | DKIM 鍵・署名設定を修正 |
4.7.32 |
From: と SPF/DKIM の組織ドメイン不整合 |
From: 設計を見直す |
5.7.25 |
PTR / 逆引き不備 | 送信 IP の逆引きを整える |
Google の FAQ でも、これらのエラーと対処方針が明示されています。問い合わせフォームで特に多いのは 4.7.32 のアラインメント不一致です。
最後の判断基準
以下の 3 条件を同時に満たしていれば、問い合わせフォーム通知の設計は堅いと言えます。
From:がexample.com配下Reply-To:がフォーム利用者アドレスAuthentication-Resultsでdmarc=passが出る
この 3 つが揃っていれば、SendGrid・SES・Mailgun・共有ホスティング・SMTP ライブラリのどれを使っていても、設計としては筋が通っています。逆に、どれか 1 つでも欠けるなら、まず From: 設計から疑うのが最短です。
参考リンク
仕様と各サービスの一次情報です。DNS に入れる実際の値は、必ず利用中のサービスが提示する値を優先してください。
仕様(RFC)
- RFC 5321 - Simple Mail Transfer Protocol ─ エンベロープ、
MAIL FROM、Return-Pathの扱い - RFC 5322 - Internet Message Format ─
From:Sender:Reply-To:の意味づけ - RFC 7208 - Sender Policy Framework (SPF) ─ DNS 参照回数の上限を含む SPF の仕様
- RFC 6376 - DomainKeys Identified Mail (DKIM) Signatures ─ セレクタ、
d=、署名対象 - RFC 7489 - Domain-based Message Authentication, Reporting, and Conformance (DMARC) ─ アラインメント、
p=、レポートの外部送信先 - RFC 3464 - An Extensible Message Format for Delivery Status Notifications ─ バウンス(DSN)の読み方
受信側のガイドライン
- メール送信者のガイドライン - Gmail ヘルプ ─ SPF / DKIM / DMARC、PTR、
From:の一致要件 - Gmail の SMTP に関するエラーとコード - Google Workspace 管理者ヘルプ ─
5.7.x/4.7.xの意味と対処
送信サービス・実装
- How to Set Up Domain Authentication - SendGrid ─ CNAME 方式、Custom Return Path
- Configuring a custom MAIL FROM domain - Amazon SES ─ MX と SPF の要件
- Easy DKIM in Amazon SES ─ 3 つの CNAME
- Domains - Mailgun Documentation ─ 送信ドメインの検証に必要なレコード
- PHP: mail - Manual ─ ヘッダの扱いと
additional_params(-f) - swaks - Swiss Army Knife for SMTP ─ 実送信テスト
関連する記事
同じタグを共有する最新の記事です。さらに近い話題で知識を深められます。
中小企業向けの一斉メール配信を、特定サービスに縛られず設計する方法
Bcc一斉送信を避け、中小企業が数十〜数百件規模の案内メールを個別送信・同意管理・配信停止・配信品質まで含めて設計する手順を整理します。
情報セキュリティ10大脅威 2026 ── ランキングの眺め方と、中小企業が本当に対策すべきもの
IPA「情報セキュリティ10大脅威2026」では、ランサム攻撃が11年連続の1位、サプライチェーン攻撃が2位、初選出の「AIの利用をめぐるサイバーリスク」が3位に入りました。組織編トップ10の内容と、中小企業がどの脅威を自分事として対策すべきかを解説します。
「何秒で動けば満足か」を決め忘れないために ── IPA「非機能要求グレード」で非機能要件を整理する
「速度が遅い」「障害対応が想定外」と揉める原因の多くは、非機能要件の決め忘れです。IPA「非機能要求グレード」の6大項目、グレード表とモデルシステムの使い方、現実的な活用方法を発注側に分かりやすく解説します。
ホームページの発注側も知っておきたい ── IPA「安全なウェブサイトの作り方」をチェックリストとして使う
会社のホームページのセキュリティは何を基準に確認すべきか。IPA「安全なウェブサイトの作り方」が取り上げる11の脆弱性と対策を、発注側・運営側にも分かる言葉で解説し、発注・検収・運用での使い方を紹介します。
中小企業のセキュリティ対策、何から始めるか ── IPA「中小企業の情報セキュリティ対策ガイドライン」第4.0版の歩き方
中小企業のセキュリティ対策は何から始めるべきか。IPA「中小企業の情報セキュリティ対策ガイドライン」第4.0版をもとに、情報セキュリティ6か条、5分でできる自社診断、SECURITY ACTIONまで段階的に解説します。
関連トピック
このテーマと近いトピックページです。記事を起点に、関連するサービスや他の記事へ進めます。
Windows技術トピック
Windows 開発、不具合調査、既存資産活用の技術トピックをまとめた入口です。
Web制作・SEOトピック
ホームページ制作、SEO対策、サービスページ設計、内部リンク、問い合わせ導線改善をまとめた入口です。
このテーマがつながるサービス
この記事は次のサービスページにつながります。近い入口からご覧ください。
HP制作
問い合わせフォームの設計、通知メールの差出人運用、Reply-To 設計を含めた問い合わせ導線の整理は、ホームページ制作と一緒に進めやすいテーマだからです。
技術相談・設計レビュー
SPF / DKIM / DMARC、外部 SMTP サービス(SendGrid / SES / Mailgun)、共有ホスティング、PHP mail() のどれを使うかは、現状構成と要件に合わせた設計レビューとして整理しやすいからです。
よくある質問
この記事のテーマについて、相談時によくある質問をまとめています。
- 問い合わせフォームのメールが届かない一番多い原因は何ですか?
- SMTPの接続自体ではなく、見えている差出人(From:)と実際に認証される差出人(SPFのMAIL FROM / DKIMのd=)が噛み合っていないことです。特に多いのは、フォーム利用者のGmailアドレスをそのままFrom:に入れる設計です。サイトのSMTPから送るのにFrom: taro@gmail.comとすると、認証されるのはサイト側ドメインなのにFrom:はGmailというズレが起き、DMARCのアラインメントに失敗します。
- 問い合わせフォームの通知メールのFromはどう設定すべきですか?
- From:は自サイトのドメインに固定し、フォーム利用者のアドレスはReply-To:に入れるのが基本です。これで返信のしやすさを確保しつつ、見える差出人と認証済み差出人がドメインで揃うため到達率が安定します。Sender:は作者と実際の送信主体が異なるときだけ使い、Return-Pathはヘッダを手書きするのではなく、MTAやメールサービス側でエンベロープ送信者として設定します。
- メール不達の調査はまず何をすればよいですか?
- コードを見る前に、届いたメールの生ヘッダを見ることです。Gmailなら「メッセージのソースを表示」から、Authentication-Results、Return-Path、From、DKIM-Signatureを確認します。最優先はFrom:のドメイン、Return-Path:のドメイン、そしてspf / dkim / dmarcがpassしているかの確認です。dmarc=failの場合は、認証失敗なのかalignment failureなのかを見分けます。DNS側はdigやnslookupでSPF・DKIM・DMARCの3レコードを引いて確認します。
- DMARCはいきなりrejectに設定してよいですか?
- いきなりrejectにするより、まずp=noneの観測モードで流量と正規送信源を確認してから、quarantine、rejectへ段階的に上げるほうが安全です。p=noneは監視のみ、quarantineは隔離推奨、rejectはSMTP中の拒否推奨という意味です。また、転送はSPFを壊しやすく、中継で本文やヘッダが書き換わるとDKIMも壊れるため、SPFだけに依存せずDKIMを必ず有効化しておくことも重要です。