2026年8月31日
2026年8月31日
OpenDKIMでDKIM署名を設定する方法(Postfix連携・DNS登録・動作確認)
自分で運用しているPostfixのメールサーバーから送るメールにDKIM署名を付けるには、OpenDKIMをmilter(メールの中継途中で処理を差し込む仕組み)としてPostfixにつなぎ、公開鍵をDNSのTXTレコードに登録します。この記事では、Ubuntu/Debianを例に、鍵の作成、OpenDKIMの設定、Postfixとの連携、DNSへの登録、署名が付いているかの確認と、つまずきやすいエラーの読み方までを順に説明します。WordPressの wp_mail() がこのサーバー経由で送るメールにも、送信元ドメインが一致していれば同じ署名が付きます。
DKIMで何が変わるのか
DKIMは、送信側のサーバーがメールのヘッダーと本文から計算した署名を DKIM-Signature ヘッダーとして付け、受信側がDNSに公開された公開鍵でその署名を検証する仕組みです。検証に成功すると、そのメールが署名したドメインの管理者の鍵で署名され、途中で書き換えられていないことが分かります。
SPFが「どのサーバーから送ってよいか」を示すのに対し、DKIMは「メールそのものが改ざんされていないか」を示します。転送されるとSPFは失敗しやすい一方、DKIMは本文や対象ヘッダーが変わらなければ転送後も検証できます。DMARCはこの2つの結果とFromのドメインの一致を見て判定するため、DKIMはDMARCを運用する前提にもなります。
GmailやYahoo!メールなどの大手は、一定以上の量を送る送信者に対してSPF・DKIM・DMARCの設定を求める方針を2024年から段階的に強めています。対象となる送信量や細かな条件は変わることがあるため、各社の送信者向けガイドラインで最新の内容を確認してください(2026年10月現在)。
作業の前提
- Postfixが動いていて、外部へのメール送信ができていること。
- 署名するドメインを
example.com、セレクター(鍵を区別する名前)を202610とします。セレクターは任意の文字列ですが、作成した年月にしておくと、後で鍵を入れ替えるときに新旧を区別しやすくなります。 - DNSのTXTレコードを編集できること。
作業前に /etc/postfix/ をバックアップし、可能なら検証用のサーバーやドメインで先に試します。
なお、OpenDKIMは長く使われている定番の実装ですが、正式リリースの間隔が長く開いている状態が続いています。新しく構築する場合は、DKIM署名の機能を持つRspamdや、dkimpy-milterといった選択肢もあります。ここではディストリビューションの標準パッケージで導入しやすいOpenDKIMを使います。
OpenDKIMを入れて鍵を作る
sudo apt install opendkim opendkim-tools
sudo mkdir -p /etc/opendkim/keys/example.com
sudo opendkim-genkey -b 2048 -d example.com -D /etc/opendkim/keys/example.com -s 202610 -v
sudo chown -R opendkim:opendkim /etc/opendkim
sudo chmod 700 /etc/opendkim/keys/example.com
sudo chmod 600 /etc/opendkim/keys/example.com/202610.private
opendkim-genkey は、秘密鍵の 202610.private と、DNSに登録する内容を書いた 202610.txt を作ります。鍵の長さは2048ビットが現在の一般的な選択です。1024ビットはすでに弱いと見なされつつあるため、新しく作るなら2048ビットにします。
秘密鍵は、これが漏れると第三者があなたのドメインの署名を作れてしまうファイルです。所有者を opendkim にして他のユーザーから読めないようにし、Gitなどのリポジトリには入れません。サーバーのバックアップに含める場合は、バックアップ先の権限も確認しておきます。
OpenDKIMを設定する
/etc/opendkim.conf の主な項目を次のようにします。パッケージに最初から書かれている項目と重なる場合は、同じ項目が二重にならないよう既存の行を書き換えます。
Syslog yes
UMask 007
Mode sv
Canonicalization relaxed/simple
OversignHeaders From
KeyTable refile:/etc/opendkim/key.table
SigningTable refile:/etc/opendkim/signing.table
ExternalIgnoreList refile:/etc/opendkim/trusted.hosts
InternalHosts refile:/etc/opendkim/trusted.hosts
Socket inet:8891@localhost
UserID opendkim
Mode svは、送信するメールに署名(s)し、受信したメールの署名を検証(v)する指定です。Canonicalization relaxed/simpleは、ヘッダーの空白の揺れなどは許容し、本文は厳しめに扱う指定で、広く使われている組み合わせです。OversignHeaders Fromは、署名後に別のFromヘッダーを追加されても検証に失敗するようにする指定です。Socket inet:8891@localhostは、Postfixとローカルの8891番ポートで通信する指定です。Unixソケットを使う方法もありますが、Postfixのchroot環境との兼ね合いで権限の問題が起きやすいため、ここではTCPを使います。外部から8891番に接続できないよう、localhostで待ち受けていることを後で確認します。
続いて、3つのファイルを作ります。
# /etc/opendkim/key.table
202610._domainkey.example.com example.com:202610:/etc/opendkim/keys/example.com/202610.private
# /etc/opendkim/signing.table
*@example.com 202610._domainkey.example.com
# /etc/opendkim/trusted.hosts
127.0.0.1
::1
localhost
key.table は「どの名前の鍵がどのファイルか」、signing.table は「どの送信元アドレスにどの鍵で署名するか」を表します。signing.table で refile: を使っているのは、*@example.com のようなワイルドカードを使うためです。
trusted.hosts に載ったホストから届いたメールは「内部から送られたもの」として署名の対象になります。ここに載っていないホストからのメールは、外部から届いたメールとして検証だけが行われます。同じサーバー上のWordPressから送る場合は 127.0.0.1 で足ります。別のサーバーのWordPressからこのPostfixを中継に使う場合は、そのサーバーのIPアドレスを追加します。
sudo systemctl restart opendkim
sudo systemctl status opendkim
sudo ss -ltnp | grep 8891
ss の結果で、待ち受けが 127.0.0.1:8891(または [::1]:8891)になっていれば、外部に開いていません。
Postfixにmilterを登録する
sudo postconf -e 'milter_default_action = accept'
sudo postconf -e 'smtpd_milters = inet:localhost:8891'
sudo postconf -e 'non_smtpd_milters = $smtpd_milters'
sudo systemctl reload postfix
smtpd_milters はSMTP経由で受け付けたメール、non_smtpd_milters は sendmail コマンドなどサーバー内から投入されたメールに適用されます。WordPressがPHPの mail() で送る場合は sendmail 経由になるため、non_smtpd_milters の指定が要ります。
milter_default_action = accept は、OpenDKIMが止まっているときでもメールの送受信は止めない(署名なしで通す)指定です。署名なしで送ることを避けたい場合は tempfail にすると、OpenDKIMが復旧するまでメールがキューに残ります。どちらを優先するかは運用方針で決めます。
すでにほかのmilter(ウイルス検査など)を使っている場合は、smtpd_milters にカンマ区切りで並べます。
DNSに公開鍵を登録する
sudo cat /etc/opendkim/keys/example.com/202610.txt
中身は次のような形です(値は省略しています)。
202610._domainkey IN TXT ( "v=DKIM1; h=sha256; k=rsa; "
"p=MIIBIjANBgkqh...(長い文字列)..."
"...(続き)..." ) ; ----- DKIM key 202610 for example.com
DNSの管理画面では、次のように登録します。
- ホスト名(名前):
202610._domainkey(管理画面によっては202610._domainkey.example.comとドメインまで含めて入れる形式です) - 種類: TXT
- 値:
v=DKIM1; h=sha256; k=rsa; p=に続けて、ファイル内で引用符ごとに分かれているp=の文字列をつなげたもの
2048ビットの鍵は、TXTレコードの1つの文字列の上限(255バイト)を超えます。DNSの仕組みとしては1つのTXTレコードの中に複数の文字列を並べて表現し、受信側はそれをつなげて読みます。管理画面が長い値を自動で分割してくれるもの、自分で引用符で区切って入れる必要があるものなど、事業者によって扱いが違うため、登録後に次の方法で中身を確かめます。
dig +short TXT 202610._domainkey.example.com
sudo opendkim-testkey -d example.com -s 202610 -vvv
opendkim-testkey の結果に key OK と出れば、DNSの公開鍵とサーバーの秘密鍵が対応しています。key not secure という表示は、そのドメインでDNSSECが使われていないという意味で、DKIMの検証自体には影響しません。DNSの反映には時間がかかることがあるため、登録直後に見つからない場合は少し待ってから再実行します。
署名されているかを確認する
- ログを見る: テストメールを外部に送り、
/var/log/mail.log(またはjournalctl -u opendkim)にDKIM-Signature field added (s=202610, d=example.com)のような行が出るかを確認します。 - 受信側で見る: Gmailなどの外部アドレスに送り、メールのソース(原文)を表示します。
Authentication-Resultsヘッダーにdkim=pass header.d=example.comが含まれていれば、受信側で検証に成功しています。表示メニューの名前はメールサービスによって異なります。 - WordPressから送る: パスワードリセットなどのメールを送り、同じように確認します。WordPressの既定の送信元は
wordpress@に続けてサイトのドメインが入ったアドレスです。そのドメインがsigning.tableの対象と違う場合は署名されないため、送信元アドレスを署名するドメインにそろえます。
うまくいかないときの確認順
ログの文言から原因を絞り込めます。起きやすい順に並べます。
- **
no signing table match for ...**: 送信元アドレスがsigning.tableのどの行にも一致していません。ログに出ているアドレスのドメインを確認します。WordPressの送信元がサーバーのホスト名(wordpress@server1.example.netなど)になっていることがよくあります。 - 署名も検証のログも出ない: Postfixがmilterに接続できていない可能性があります。
mail.logにconnect to Milter service inet:localhost:8891: Connection refusedが出ていないかを見て、systemctl status opendkimでOpenDKIMが動いているか、Socketの指定とPostfix側の指定が一致しているかを確認します。 - 署名されず、検証だけが行われている: 送信元のホストが
trusted.hostsに入っていません。別サーバーのWordPressから中継しているときに起こりやすい症状です。 - **
can't load key from file**: 秘密鍵のパスがkey.tableと合っていないか、opendkimユーザーが読めない権限になっています。 - **受信側で
dkim=failや公開鍵が見つからない**: DNSの値の途中に余計な空白や引用符が入った、長い値が途中で切れた、セレクター名が違う、のいずれかが多い原因です。digの結果を202610.txtと見比べます。 - 署名は付くが、メーリングリスト経由だけ失敗する: リストが件名や本文を書き換えると、署名の検証は失敗します。これは仕組み上起こりうることで、DMARCの運用方針と合わせて考えます。
鍵の入れ替え
同じ鍵を長く使い続けるより、定期的に入れ替えるほうが、鍵が漏れたときの影響を小さくできます。入れ替えは次の順で行うと、配送中のメールの検証を失敗させずに済みます。
- 新しいセレクター(例:
202704)で鍵を作り、DNSに公開する。 - DNSに反映されたことを
opendkim-testkeyで確かめてから、key.tableとsigning.tableを新しい鍵に切り替えて再起動する。 - 数日から一週間ほど待ち、古いセレクターのTXTレコードを削除する。
まとめ
- DKIMは送信メールに署名し、受信側がDNSの公開鍵で改ざんの有無と署名ドメインを確かめる仕組みで、DMARCの前提になります。
- OpenDKIMは
KeyTable・SigningTable・trusted.hostsの3つで「どの鍵で、どのアドレスに、どこからのメールに署名するか」を決めます。 - Postfixには
smtpd_miltersとnon_smtpd_miltersの両方を設定すると、WordPressがサーバー内から送るメールも署名されます。 - 2048ビットの公開鍵はTXTの値が長いため、登録後に
digとopendkim-testkeyで中身を確認します。 - 署名されないときは、送信元アドレスのドメインと
signing.table、送信元ホストとtrusted.hostsの対応から確認します。