送信ドメイン認証 (SPF / DKIM / DMARC)
作成: Shintaro / Acia
対象OS: Debian 13 (Sakura VPS)
対象ドメイン: <DOMAIN>(例: example.com)
メールホスト: <MAIL_HOST>(例: mail.<DOMAIN> → mail.example.com)
目的
送信ドメイン認証(SPF / DKIM / DMARC)を適切に設定し、
- なりすましメールの抑止
- スパム判定・迷惑メール行きリスクの低減
- 自ドメインメールサービスの信頼性向上
を実現する。
このドキュメントは Debian 13 + Postfix 3.9 + Dovecot + OpenDKIM を前提とし、
将来の 完全再構築 においてもそのまま再現できることを目的とする。
前提
- 既に以下が構成済みであること
- 06_apache.md による HTTPS + certbot 導入
- 07_postfix.md による Postfix 基本構成(Maildir / SMTP Submission / SMTPS)
- 08_dovecot.md による Dovecot(IMAPS / POP3S / SASL連携)
- TLS 証明書は Apache / Postfix / Dovecot で共用
/etc/letsencrypt/live/<DOMAIN>/fullchain.pem
/etc/letsencrypt/live/<DOMAIN>/privkey.pem
- DNS ゾーンは さくらインターネットの「ドメインコントロールパネル」を利用
- SPF レコードは次の形をベースとする:
@ IN TXT "v=spf1 ip4:<SERVER_IPV4> -all"
SPF(Sender Policy Framework)
方針
- 送信元を 自前VPS のみ に限定する。
- 将来、外部サービス(例: Gmail, メール配信サービス)を使う場合は
include:を追加する。
推奨レコード
@ 3600 IN TXT "v=spf1 ip4:<SERVER_IPV4> -all"
<SERVER_IPV4>: VPS のグローバル IPv4 アドレス
代替レコード例(MX ベース運用)
将来、MX で指しているサーバ郡をまとめて許可したい場合は以下の形式も利用可能。
@ 3600 IN TXT "v=spf1 mx -all"
外部サービス追加例
Gmail など外部MTAを併用する場合は include: を追加する。
@ 3600 IN TXT "v=spf1 ip4:<SERVER_IPV4> include:_spf.google.com -all"
SPF は 255 文字制限・DNS クエリ回数制限があるため、
include:を増やしすぎないように注意する。
DKIM(OpenDKIM)
役割と構成
- 秘密鍵でメールに署名し、DNS上の公開鍵で受信側が検証できるようにする仕組み。
- 本構成では、Postfix → OpenDKIM へ milter 経由で接続し、送信時に自動で DKIM 署名される。
flowchart LR Postfix -- Milter --> OpenDKIM OpenDKIM -- 検証用公開鍵 --> DNS
パッケージインストール
sudo apt update
sudo apt install -y opendkim opendkim-tools
ディレクトリ構成(例)
/etc/opendkim/
├── keys/
│ └── <DOMAIN>/
│ ├── mail.private … 秘密鍵
│ └── mail.txt … 公開鍵(DNS登録用)
├── KeyTable
├── SigningTable
└── TrustedHosts
鍵生成(selector=mail)
sudo mkdir -p /etc/opendkim/keys/<DOMAIN>
cd /etc/opendkim/keys/<DOMAIN>
sudo opendkim-genkey -b 2048 -r -s mail -d <DOMAIN>
sudo chown opendkim:opendkim mail.private
sudo chmod 600 mail.private
OpenDKIM 本体設定 /etc/opendkim.conf
以下の設定をベースに調整:
Syslog yes
Umask 002
KeyTable /etc/opendkim/KeyTable
SigningTable refile:/etc/opendkim/SigningTable
InternalHosts /etc/opendkim/TrustedHosts
ExternalIgnoreList /etc/opendkim/TrustedHosts
Canonicalization relaxed/simple
Mode sv
OversignHeaders From
Socket inet:8891@localhost
UserID opendkim:opendkim
PidFile /run/opendkim/opendkim.pid
# 任意(デバッグ用)
LogWhy yes
AutoRestart Yes
AutoRestartRate 10/1h
PidFileを明示しないと、systemd 起動がタイムアウトする事例あり。必ず指定する。Socketは TCP:8891 で Postfix から接続される。LogWhyは署名失敗時の原因分析用ログ出力(初期導入時に有効推奨)
テーブル定義
/etc/opendkim/KeyTable
mail._domainkey.<DOMAIN> <DOMAIN>:mail:/etc/opendkim/keys/<DOMAIN>/mail.private
/etc/opendkim/SigningTable
*@<DOMAIN> mail._domainkey.<DOMAIN>
/etc/opendkim/TrustedHosts
127.0.0.1
::1
localhost
ローカルホスト以外を信頼ホストに含めないことで、署名漏れを防止する。
Postfix との連携(main.cf)
/etc/postfix/main.cf に以下を追記:
milter_default_action = accept
milter_protocol = 2
smtpd_milters = inet:localhost:8891
non_smtpd_milters = inet:localhost:8891
milter_macro_daemon_name = ORIGINATINGは main.cf には 書かず、master.cf側の submission/smtps の-oで個別指定する。
サービス起動と連携確認
sudo systemctl restart opendkim
sudo systemctl reload postfix
sudo systemctl status opendkim
sudo journalctl -u opendkim -n 50
legacy: /etc/default/opendkim の扱い
Debian 13 以降の systemd 構成ではこのファイルは使用されない。
ファイルが存在していても、現在の systemctl に影響を与えることはない。
/etc/default/opendkimは legacy 互換用として残されており、 Socket 等の指定は/etc/opendkim.confに集約されている。
DNS 登録(公開鍵)
/etc/opendkim/keys/<DOMAIN>/mail.txt に以下のような形式で出力される:
mail._domainkey IN TXT (
"v=DKIM1; k=rsa; p=<公開鍵文字列>" )
さくらのドメインコントロールパネルでは:
- エントリ名:
mail._domainkey - タイプ:
TXT - 値:
"v=DKIM1; k=rsa; p=..."(改行・コメント除去し1行に整形)
TXT が255文字を超える場合、quoted-string を複数に分割して1レコードに収めること。 TXTレコードを2本に分けると
opendkim-testkeyが失敗する。
DMARC
役割
- SPF / DKIM の認証結果に基づき、
受信側に対して「認証失敗メールをどう扱うか」のポリシーを通知する仕組み。
- レポートメール(
rua,ruf)を通じて、なりすましや設定不備を検知できる。
DMARC レコード基本形
DMARC レコードは _dmarc.<DOMAIN> の TXT として定義する。
現在の構成(p=quarantine)
実際の運用では、すでに SPF/DKIM/DMARC がすべて pass していることが確認できており、
ポリシーは以下のように quarantine モードに引き上げ済み:
_dmarc.<DOMAIN>. 3600 IN TXT "v=DMARC1; p=quarantine; rua=mailto:postmaster@<DOMAIN>; fo=1"
p=quarantine: 認証失敗メールを迷惑メールフォルダ等に隔離rua: 集計レポート送信先fo=1: SPFまたはDKIMのどちらかがfailした場合にもレポート収集
Gmailからのレポートで
spf=passdkim=passdmarc=passを確認済(2025-11-27)
1. 初期導入(p=none / 観測モード)
_dmarc.<DOMAIN>. 3600 IN TXT "v=DMARC1; p=none; rua=mailto:<POSTMASTER_ADDR>"
p=none: 認証失敗時も配送は許可し、レポートのみ収集rua: 集計レポート送付先(一般に postmaster 相当のアドレス)
2. 段階的強化(quarantine)
運用に問題がないことを確認後、隔離ポリシーへ引き上げる。
_dmarc.<DOMAIN>. 3600 IN TXT "v=DMARC1; p=quarantine; rua=mailto:<POSTMASTER_ADDR>; ruf=mailto:<ADMIN_ADDR>; fo=1"
p=quarantine: 認証失敗メールを迷惑メールフォルダ等に隔離ruf: フォレンジックレポート送付先fo=1: SPF または DKIM が失敗した場合にレポートを要求
一部プロバイダ(例: Gmail)は
ruf(フォレンジックレポート)をサポートしない。 必須ではないため、不要であればrufは省略してよい。
3. 最終段階(reject)
問題がなければ最終的に p=reject へ引き上げる。
_dmarc.<DOMAIN>. 3600 IN TXT "v=DMARC1; p=reject; rua=mailto:<POSTMASTER_ADDR>; fo=1"
検証手順
1. SPF の確認
digやnslookupで TXT レコードを参照し、意図した値になっているか確認。
例:
dig TXT <DOMAIN> +short
dig TXT _dmarc.<DOMAIN> +short
dig TXT mail._domainkey.<DOMAIN> +short
- SPF 評価ツール(外部サービス)でもチェックしておくと安心。
2. DKIM キー検証
OpenDKIM のテストコマンドで DNS と鍵の整合性を確認。
sudo opendkim-testkey -d <DOMAIN> -s mail -vvv
key OKと表示されれば DNS / 鍵ともに問題ない。key not secureは DNSSEC 未使用の警告で、致命的ではない。
3. 実メール送信テスト(swaks)
swaks を利用して、実際に DKIM 署名・SPF 判定を確認する。
swaks の導入(TLS依存込み)
--tls を使うため Net::SSLeay / IO::Socket::SSL が必要。
sudo apt update
sudo apt install -y swaks libnet-ssleay-perl libio-socket-ssl-perl
テスト送信
**送信元(From / envelope-from)は <MAIN_USER>@<DOMAIN> に揃えること。**
ホスト名由来のサブドメイン(例: server.<DOMAIN>)で送ると Gmail により未認証扱いで拒否されたため、設計として必須条件にする。
read -s -p "SMTP password: " SMTPPASS; echo
swaks --to you@example.net \
--from <MAIN_USER>@<DOMAIN> \
--header "From: <MAIN_USER>@<DOMAIN>" \
--server localhost \
--auth-user <MAIN_USER> \
--auth-pass "$SMTPPASS" \
--auth PLAIN \
--tls
unset SMTPPASS
受信側でメールヘッダを確認し、以下のような Authentication-Results を確認する。
spf=pass(sender IP is authorized)dkim=pass(signature verified)dmarc=pass(policy evaluation successful)
4. Gmail 受信ヘッダ検証(実機結果 / 2025-11-21)
実機検証結果:
- 送信元を
<MAIN_USER>@server.<DOMAIN>とした場合
Gmail 側で SPF/DKIM did not pass と判定され 550-5.7.26 unauthenticated sender でブロック。
- 送信元を
<MAIN_USER>@<DOMAIN>に揃えた場合
Gmail へ配送成功。Authentication-Results は以下の通り。
結果:
- SPF: PASS
- DKIM: PASS
- DMARC: FAIL(DMARC レコード未設定のため) → 初回は迷惑メールフォルダに分類
ヘッダ抜粋(要旨):
spf=pass
dkim=pass
dmarc=fail (no DMARC policy found)
Postfix 配送ログ(journalctl)抜粋:
status=sent (250 2.0.0 OK - gsmtp)
DMARC を設定すると、以後の Gmail での迷惑判定率が大きく改善する。
運用ノート
- DNS 伝播には数分〜数時間かかる場合があるため、
設定変更後すぐに結果が反映されないことがある。
- DMARC は段階導入(
none → quarantine → reject)とし、
レポートを見ながら少しずつポリシーを強める。
- OpenDKIM / Postfix のログは以下で確認可能。
sudo journalctl -u opendkim
sudo journalctl -u postfix
sudo tail -f /var/log/mail.log
- certbot による証明書更新時(06_apache.md 参照)は、
Postfix / Dovecot が新証明書を読めているかを確認する。
sudo systemctl reload postfix
sudo systemctl reload dovecot
- 外部メールサービスを追加した際は、必ず SPF / DKIM / DMARC への影響を確認する。
特に SPF の -all は厳格であるため、許可し忘れがあると正当なメールが拒否される。
変更履歴
| 日付 | 編集者 | 内容 |
|---|---|---|
| 2025-10-28 | Shintaro / Acia | 初版作成。SPF/DKIM/DMARC の最小構成と段階導入手順を記載。 |
| 2025-10-29 | Shintaro / Acia | ユーザ名・メールアドレスを変数化し、教材用途での汎用性を強化。 |
| 2025-11-21 | Shintaro / Acia | SPF(ip4 指定)を前提に再構成。KeyTable/SigningTable/TrustedHosts を明示し、Debian 13/Postfix 3.9 + OpenDKIM 連携手順を確定。Gmail での配送ブロック→PASS までの実機検証結果(Fromドメイン一致、TXT文字数制限の対処、PidFile明示)を追記。 |