SPFとは
SPF(Sender Policy Framework)は「このドメインから送るメールはどの送信元IPから送られるべきか」をDNS(TXTレコード)で宣言し、受信側が SMTP セッション中の送信元IPと照合して正当性を確認する仕組みです。ヘッダの From は使いません(From は DMARC で整合性を見る対象)。
受信サーバーが「何を参照して」判定するか
SPFが参照するのはメールヘッダではなく、SMTPセッションのエンベロープ情報です。
-
接続情報(SMTPレイヤ)
- 送信元IPアドレス(client IP)
- HELO/EHLO で名乗ったドメイン名
- MAIL FROM(エンベロープFrom)のアドレス
- SPFが使うのはこのアドレスの「ドメイン部分」
- MAIL FROM が空(<> のバウンス等)の場合は HELO/EHLO ドメインを評価対象とする
-
DNS情報
- 対象ドメインの TXT レコード中の SPF レコード(v=spf1 ...)
-
受信後に付与されるヘッダ(参考)
- Return-Path: 受信サーバーが最終配送時に付与。MAIL FROM の痕跡。SPFの評価入力そのものではない
- Authentication-Results: SPFの評価結果が記録される標準ヘッダ(例: spf=pass smtp.mailfrom=example.com)
- Received-SPF: 実装依存の結果ヘッダ(参考情報)
判定の全体フロー
-
TCP接続受理(SMTPセッション開始)
- 受信サーバーはクライアントの送信元IPを記録
-
HELO/EHLO を受信
- 例: EHLO mail.sender.tld
-
MAIL FROM を受信
- 例: MAIL FROM:bounce@sender.example
- 判定対象ドメインを決定
- MAIL FROM が非空 -> sender.example
- MAIL FROM が空(<>) -> HELO/EHLO で名乗ったドメイン
-
SPFレコード取得(DNS)
- 対象ドメインの TXT レコードから v=spf1 を探す
- 注意点:
- TXTが複数あり v=spf1 が2つ以上ある場合は permerror
- include/redirect/a/mx/exists 等の評価で発生するDNSルックアップの合計は最大10回
-
SPFレコード評価
- 左から右へメカニズムを順次評価
- 対応メカニズム例:
- ip4、ip6: アドレス/プレフィックスで合致確認
- a、mx: それぞれのレコードが解決するIPと照合
- include: 参照先ドメインのSPFを再帰的に評価(合致すれば include がマッチ)
- exists: 指定ドメインの存在チェックで判定
- ptr: 非推奨
- redirect: 評価対象を別ドメインへ切替(最終的な結論はredirect先で決まる)
- 修飾子(クオリファイア)
- +(省略時のデフォルト): 合致で pass
-
- : 合致で fail
- ~ : 合致で softfail
- ? : 合致で neutral
-
判定結果の決定
- 代表的な結果
- pass: 許可IPにマッチ
- fail: 明示的に拒否(例: -all)
- softfail: 推奨されないが拒否まではしない(例: ~all)
- neutral: 可否を表明していない
- none: 対象ドメインにSPF未設定
- temperror: DNS一時障害
- permerror: レコード不正、ルックアップ上限超過等
- 受信サーバーは結果に応じて受信可否、スコアリング、隔離などのポリシーを適用
- 代表的な結果
-
結果ヘッダの付与(受信後)
- Authentication-Results を付与(推奨)
- 例:
Authentication-Results: mx.example.jp; spf=pass smtp.mailfrom=sender.example
- 例:
- 実装により Received-SPF も付与されることがある
- Authentication-Results を付与(推奨)
SMTPセッション例
S: 220 mx.example.jp ESMTP
C: EHLO mail.sender.tld
S: 250-mx.example.jp ...
C: MAIL FROM:<bounce@sender.example>
S: 250 2.1.0 Ok
C: RCPT TO:<user@example.jp>
S: 250 2.1.5 Ok
...
- 受信サーバーは MAIL FROM から sender.example を抽出して SPF 対象ドメインにする
- MAIL FROM が <> の場合は HELO 名(mail.sender.tld)で SPF を評価
SPFレコードの書式と評価イメージ
-
例1(シンプル):
- レコード: v=spf1 ip4:203.0.113.5 -all
- クライアントIPが 203.0.113.5 -> pass
- それ以外 -> fail(-all)
-
例2(複数経路と include):
- レコード: v=spf1 a mx include:_spf.provider.com ~all
- 送信元IPが自ドメインのA/MX解決先または provider のSPFに含まれていれば pass
- ※「provider」= 対象ドメインのメールを送る外部の送信サービス(ESP)や上位SMTPリレー(セキュリティゲートウェイのアウトバウンドなど)
- いずれにも該当しなければ softfail(~all)
-
例3(バウンス/MAIL FROM が空)
- MAIL FROM: <>
- HELO: mx.sender.example
- 対象: mx.sender.example のTXTレコード(v=spf1 ...)を使って評価
どのヘッダを見れば人間が結果を確認できるか
- SPF評価そのものはヘッダを参照しないが、受信後に以下を見ると結果が確認できる
- Authentication-Results: spf=pass/fail/... と対象(smtp.mailfrom / smtp.helo)が記録される
- Return-Path: 最終配送時に付与。MAIL FROM の痕跡として参照(SPF入力ではない)
- Received-SPF: 実装により付与(非標準)
例:
Return-Path: <bounce@sender.example>
Authentication-Results: mx.example.jp; spf=pass smtp.mailfrom=sender.example
実装時の注意点・落とし穴
- FromヘッダはSPF評価に使わない(DMARCでFrom整合性を確認)
- 10回のDNSルックアップ上限に注意(include や a/mx を多用すると超えがち)
- 転送(forward)でSPFが壊れる問題
- 転送サーバーから送ると送信元IPが変わるためSPF failになりやすい
- 実運用は転送側で SRS(Sender Rewriting Scheme)を導入するとよい
- ※「SRS」=メール転送サーバーが「エンベロープ送信者(MAIL FROM/Return-Path)」を自分のドメインのアドレスに書き換える仕組み
- TXTに複数の v=spf1 を置かない(permerror)