優れたメール用DNSレコードのトラブルシューティングは、ある不都合な事実から始まります。SPF、DKIM、またはトラッキング用CNAMEが検証できないとき、原因が公開しようとしたレコードそのものであることはまれです。多くの場合、DNS管理画面がそれをどのように保存したかが原因です。255文字を超えた鍵、二重に追加されたドメイン名、値の一部になってしまった引用符、2つ目のSPFレコード、あるいはキャッシュからまだ消えていない古い回答などです。本記事ではこれらを順に取り上げ、digとnslookupでの確認方法を示し、最後に症状別に使える表をまとめます。
メールのレコードはDNSでどのように存在するか
メール認証の方式はすべて、数種類のレコードタイプに基づいています。SPFとDKIMはTXTレコードとして公開され、DMARCは_dmarcで始まる名前のTXTレコードです。また、多くの送信プラットフォームは、リターンパスやトラッキング用のホスト名にCNAMEレコードを求めます。MXレコードは受信メールのルーティングに使われます。リゾルバは名前とタイプを指定して問い合わせ、回答にはTTL(Time to Live)が含まれます。これは、各キャッシュがその回答をどのくらいの間再利用してよいかを示します。
トラブルの大半は、次の3点で説明できます。第一に、DNS管理画面はゾーンの上に作られた使いやすいフロントエンドであり、名前、引用符、分割の扱いは画面ごとに異なります。第二に、キャッシュは複数の階層に存在するため、同じ名前でも、しばらくは場所によって異なる回答が返ることがあります。第三に、レコードタイプによっては、同じ名前に共存できないものがあります。レコード全般については認証ガイドで、検証の流れについては送信ドメインの検証で解説しています。本記事は、それらを補う診断編です。
まず確認すべき場所:権威ネームサーバー
何かを変更する前に、実際に何が公開されているかを確認してください。お使いのノートPCが使う公開リゾルバのようなものは、古い回答を保持している場合があります。権威ネームサーバーとは、ゾーンを保持し、決定的な回答を返すサーバーです。そのため、私たちは常に最初にそこへ問い合わせます。
# 1. Find the authoritative nameservers for the domain
dig NS example.com +short
# 2. Ask one of them directly for the record (no cache involved)
dig TXT selector1._domainkey.example.com @ns1.dns-host.example +noall +answer
# 3. Compare with what a public resolver says
dig TXT selector1._domainkey.example.com @9.9.9.9 +noall +answer
# 4. Check the TTL and the negative caching value
dig SOA example.com @ns1.dns-host.example +noall +answer
# nslookup equivalent
nslookup -type=TXT selector1._domainkey.example.com ns1.dns-host.example
権威サーバーの回答が誤っていれば、問題は管理画面にあるので、レコードを修正します。権威サーバーの回答が正しく、公開リゾルバの回答が異なる場合は、キャッシュが原因なので待ちます。両方とも正しいのに検証が失敗する場合は、確認している名前が誤っているか、プラットフォームが別のレコードタイプを想定している可能性が高いでしょう。この1回の比較は、本記事のどの手法よりも多くの推測を取り除きます。
ヒント:自分のDNSキャッシュを使わないマシンから確認してください。また、Webベースのチェッカーの結果は、お使いのリゾルバではなく、そのチェッカーのリゾルバの結果であることを忘れないでください。
255文字を超えるTXT文字列とDKIM 2048ビット鍵
TXTレコードは1つ以上の文字列(character-string)を保持し、各文字列は255バイトに制限されています。これは、各文字列を1バイトの長さ情報とともに保存するRFC 1035の元のDNSフォーマットに由来します。1つのレコードに複数の文字列を含めることができ、SPFとDKIMでは、受信側がそれらを順番に、スペースを加えずに連結します。両方の仕様にそう明記されています(SPFはRFC 7208、DKIMはRFC 6376)。
実際に影響が出るのはDKIMです。1024ビットRSA公開鍵をbase64にすると、バージョンや鍵タイプのタグを加えた時点で上限に近くなります。2048ビットの鍵はおよそ2倍の長さになるため、p=の値だけで数百文字になります。したがって、複数の文字列に分けて保存する必要があります。2048ビット鍵に手間をかける価値がある理由は、DKIM鍵のローテーション、セレクタ、鍵長のガイドで説明しています。
| 管理画面の動作 | 行うべきこと | 確認方法 |
|---|---|---|
| 長い値を自動で分割する | 引用符も改行も付けずに、値全体を一度だけ貼り付ける | digの出力に複数の引用符付き文字列が表示され、合わせると鍵全体になる |
| 引用符付きの断片の入力を求める | 255文字未満の任意の位置で分割し、各部分を引用符で囲み、1つのスペースで区切る | 連結したテキストが元の鍵と完全に一致する |
| 255文字を超える値を拒否する | 長いレコード用の設定や別のレコードエディタを探す。なければホスティング会社に問い合わせる | ルックアップが、切り詰められていない完全な鍵を返す |
| 値を通知なく切り詰める | 断片に分けて再入力し、結果を読み戻す | 途中で終わっている鍵は、鍵または構文エラーでDKIM検証に失敗する |
正しい分割の例
次の例は、分割されたレコードの形を示しています。鍵のテキストは説明用に作った短縮版です。実際のレコードでは、断片を合わせるとプラットフォームから提供された鍵全体になります。
selector1._domainkey.example.com. 3600 IN TXT (
"v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA"
"q1x2example0invented0key0chunk0one0aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
"IDAQAB" )
よくある落とし穴は2つあります。鍵を分割するときに鍵の内部へスペースを入れないでください。受信側は文字列を連結するため、スペースが鍵の一部になってしまいます。また、セレクタ名やタグ名の途中でレコードを切らないでください。分割した鍵が失敗する場合は、目視ではなくテキスト差分ツールを使って、連結結果を元の鍵と1文字ずつ比較してください。
レジストラとDNS管理画面の癖
同じレコードでも、4つの管理画面では4通りの入力方法になることがあります。以下は、私たちが最もよく目にする癖です。
ドメインが二重に付加される
多くの管理画面は、ゾーン名を自動で付加します。ホスト欄に selector1._domainkey.example.com と入力すると、画面は selector1._domainkey.example.com.example.com として保存することがあります。症状としては、管理画面にはレコードがあるのに、正しい名前のルックアップでは何も返らないというものです。相対部分である selector1._domainkey だけを入力してください。apexの場合は、画面に応じて@を使うか、欄を空にします。ゾーンファイルでは末尾のドットが完全修飾名を示すのが通常ですが、Web管理画面では異なるため、保存された名前をdigで読み戻して確認してください。
引用符、改行、見えない文字
Webページや文書から値をコピーすると、スマート引用符、ノーブレークスペース、改行が一緒に入り込むことがあります。さらに管理画面が独自に引用符を加えると、値の先頭に引用符の文字がそのまま入り、引用符で始まるレコードは v=spf1 や v=DKIM1 で始まらないため認識されません。まずプレーンテキストエディタに貼り付けてから管理画面に貼り付け、結果を読み戻してください。
誤ったレコードタイプまたは誤った名前
プラットフォームによっては、CNAMEを想定していた場所でTXTレコードを求めたり、その逆だったりします。指示どおりのタイプを使用してください。また、正しいゾーンを編集しているかも確認してください。ドメインがあるプロバイダのネームサーバーを使っているのに、レジストラ側のゾーンを編集した場合、その編集は一切反映されません。先に示したNSルックアップで、有効なゾーンの所在がわかります。
| 管理画面での症状 | 考えられる原因 | 対処 |
|---|---|---|
| 名前にドメインが二重に表示される | 完全な名前に対して管理画面がゾーンを付加した | 相対名だけを入力する |
| ルックアップの出力でのみ、値の先頭と末尾に引用符が1組ある | digによるTXT出力では正常 | 変更は不要 |
| 値にエスケープされた引用符や先頭の引用符が含まれる | 自分で引用符を付け、管理画面も独自に付加した | 自分で付けた引用符を削除する |
| レコードは保存されたが、ルックアップで何も返らない | 有効なネームサーバーが提供していないゾーンを編集した | NSレコードが示すプロバイダでゾーンを編集する |
| 管理画面が名前内のアンダースコアを受け付けない | 管理画面の名前検証ルール | 別のエディタモードを使うか、DNSプロバイダに問い合わせる |
apexのCNAME、フラット化、レコードの競合
CNAMEは、ある名前が別の名前のエイリアスであることを示すため、リゾルバはそれをたどり、参照先の回答を使うことになります。そのため、CNAMEは同じ名前にある他のレコードと共存できません(RFC 1034およびRFC 2181)。ドメインのルートであるapexにはSOAとNSレコードが必要で、通常はMXやTXTもあるため、apexのCNAMEは無効です。
一部のDNSプロバイダは、フラット化やエイリアスレコードタイプでこの制約を回避しています。プロバイダが自分で参照先を調べ、apexで通常のアドレスレコードを返します。これは、ルートのWebアドレスをホスティングサービスに向ける場合には役立ちますが、メール認証には役立ちません。プラットフォームがサブドメインなどのホスト名にCNAMEを求める場合は、そのサブドメインに設定してください。プラットフォームが裸のドメインにCNAMEを求める場合は、TXTとアドレスレコードなどの代替案を問い合わせてください。
競合は逆方向でも起こります。すでにTXTレコードがある名前にCNAMEを追加した場合、たとえば以前TXTとして公開していたDKIMセレクタに追加した場合、管理画面によってはどちらかが拒否されるか無視されます。CNAMEを追加する前に、古いレコードを削除してください。この状況はプロバイダ変更時によく起こります。手順の順序は移行ガイドで扱っています。
SPFレコードの重複とその他の重複
ドメインが公開できるSPFレコードは1つだけです。これは v=spf1 で始まるTXTレコードです。受信側が2つ見つけると結果は永続エラーとなり(RFC 7208)、1社のベンダーのメッセージだけでなく、すべてのメッセージでSPFが失敗します。これは、2つのチームがそれぞれのベンダーに求められたレコードを追加したときに起こります。
| 状況 | 受信側に見える結果 | 対処 |
|---|---|---|
| v=spf1 で始まるTXTレコードが2つある | 永続エラー、SPFは通過しない | すべてのincludeメカニズムを含む1つのレコードに統合する |
| レコードは1つだが、ルックアップが10回を超える | ルックアップ上限を超えた時点で永続エラー | includeをフラット化または削除する。SPFルックアップのガイドを参照 |
| _dmarcにDMARCレコードが2つある | ポリシーが無視される可能性がある | レコードを1つにする |
| 同じセレクタが異なる鍵で2回公開されている | どの鍵が選ばれるか予測できない | 古い鍵を削除するか、新しいセレクタを使う |
統合は原理的には簡単です。各レコードからincludeとip4のメカニズムを取り出し、1つの v=spf1 レコードにまとめ、末尾を単一のallクオリファイアで終えます。難しいのはルックアップ数で、SPF permerrorガイドと1つのドメインで複数のベンダーを管理する方法で解説しています。
プロキシされたレコード:メールにはDNSプロキシをオフにする
DNSプロバイダによっては、レコードの横に色付きの雲のアイコンで表示されるプロキシモードを提供しています。このモードでは、プロバイダがその名前への問い合わせにプロバイダ自身のアドレスで応答し、Webトラフィックを自社ネットワーク経由で中継します。これはWebサイトには便利ですが、メールには不向きです。
メール関連のCNAMEがプロキシされていると、ルックアップは送信プラットフォームが想定する参照先を返さなくなります。検証は失敗し、トラッキングやリターンパスのホスト名は正しいサーバーに解決されず、トラッキングドメインのHTTPS証明書が発行されないこともあります。プロキシされたメールサーバーのホスト名は、プロキシがメール用ではなくWeb用のポートを処理するため、SMTP接続をまったく受け付けません。そのため、メールに関連するすべてのレコードをDNS onlyモードに設定してください。対象は、MXの参照先、メールサーバーのAレコード、リターンパスとトラッキング用ホスト名のCNAME、DKIMのCNAMEです。TXTレコードはプロキシされないため、影響を受けません。これらのホスト名がプラットフォームに直接解決されなければならない理由は、リターンパスとトラッキングドメインのガイドで説明しています。
確認:CNAMEを保存したにもかかわらず、プロキシされた名前へのdigクエリが、お使いのプラットフォームのものではないアドレスを返す場合、それがプロキシがオンになっているサインです。
TTLの選び方と変更計画
TTLは、リゾルバが回答を保持してよい秒数です。TTLが長いとクエリが減り、ネームサーバーが一時的に利用できなくなった場合の耐性が高まります。短いTTLは、ミスからの素早い復旧を可能にします。適切な方法は、フェーズに応じて使い分けることです。
| フェーズ | 推奨TTL | 理由 |
|---|---|---|
| 新しいレコードの構築またはテスト | 300〜600秒 | 修正がすぐに反映される |
| 計画的な変更の前 | 変更のかなり前に、少なくとも現在のTTLと同じ時間をかけて下げる | 切り替え前に古いキャッシュが失効する |
| 変更当日 | 短いままにする | ロールバックできる |
| 安定したレコード | 3600秒から1日まで | クエリが減り、障害の影響を受けにくい |
変更計画の要点は、TTLを下げても即座には効果が出ないということです。すでにレコードを保持しているキャッシュは、古いTTLの間はそれを保持し続けます。レコードのTTLが86400秒なら、変更の少なくとも1日前に下げてください。そのうえで値を変更し、待ち、検証し、TTLを再び上げます。
伝播とネガティブキャッシュ
DNSの変更は、1点から広がるわけではありません。世界規模のプッシュ配信はありません。一般に伝播と呼ばれるものは、単にキャッシュが失効するまでにかかる時間のことです。権威サーバーは、ゾーンが保存されて読み込まれた時点で新しい値を返し、各リゾルバは、キャッシュされたコピーが期限切れになった時点で切り替わります。一部のリゾルバは非常に短いTTLを無視したり、回答を少し長く保持したりするため、余裕を見ておいてください。
見落としやすい第二のキャッシュが、ネガティブキャッシュです。リゾルバがまだ存在しない名前を問い合わせると、その「見つからない」という回答を記憶します。その時間はSOAレコードに基づくとRFC 2308に定められています(SOAのTTLとminimumフィールドのうち小さい方)。プラットフォームがレコードの追加の数分前にチェックしていた場合、レコードが存在するようになった後でも、この時間が切れるまで失敗がキャッシュされたままになることがあります。
具体例
あるドメインのDKIM TXTレコードが10:00にTTL 3600秒で公開され、SOAのネガティブキャッシュ時間が900秒だったとします。10:05にプラットフォームが早すぎるチェックを行い「見つからない」を受け取ると、そのリゾルバは失敗を約10:20までキャッシュします。10:10にタイプミスに気づき、鍵を修正して保存します。権威サーバーはこの時点から新しい回答を返します。10:00に最初のレコードをキャッシュしたリゾルバは、11:00まで古い回答を返す可能性があります。「見つからない」をキャッシュしたリゾルバは、10:20まで返す可能性があります。つまり、すべてのリゾルバで完全に正しい結果になるのは11:00までかかるかもしれませんが、権威サーバーに直接問い合わせるチェックなら、10:10の時点で通ります。この場合は、権威サーバーの結果で編集が正しいことを確認し、最も長いキャッシュ時間である60分を待ってから、検証ボタンを再度押します。
プラットフォームがチェックを自動で再試行する場合は、何もする必要がないかもしれません。ボタンを押したときだけチェックする場合は、算出した最も長いキャッシュ期間を待ってください。待っている間に再びレコードを変更しないでください。変更するたびに、更新されるキャッシュの時計がやり直しになります。
症状別の診断表
| 症状 | 最も可能性の高い原因 | 最初の確認 | 対処 |
|---|---|---|---|
| プラットフォームがDKIMレコードを見つけられないと表示する | 名前の二重化、誤ったゾーン、または未伝播 | 権威サーバーに対して、正確なセレクタ名をdigで確認する | ホスト欄を修正するか、キャッシュを待つ |
| DKIMは検証されるが、署名が鍵エラーで失敗する | 鍵が切り詰められた、またはスペースを入れて分割された | TXT文字列を連結し、元の鍵と比較する | スペースなしの断片で再入力する |
| SPFがpermerrorを返す | SPFレコードが2つある、またはルックアップが10回を超えている | apexのTXTをdigし、v=spf1 レコードの数を数える | レコードを統合し、ルックアップを減らす |
| SPFレコードが無視されているように見える | 値にリテラルの引用符または先頭のスペースがある | v=spf1 で始まっていない値を探す | 余分な文字を削除する |
| CNAMEが保存できない | その名前に他のレコードがある、または名前がapexである | その名前にあるすべてのレコードタイプを一覧表示する | 競合を解消するか、サブドメインを使う |
| CNAMEはあるが、検証に失敗する | DNSプロキシがオン、または参照先の入力ミス | digが期待どおりの参照先を返すか | DNS onlyに設定し、参照先を修正する |
| 自分のコンピュータでは動くが、プラットフォームでは失敗する | リゾルバのキャッシュが異なる | 権威サーバーと2つの公開リゾルバに問い合わせる | 古いTTLが切れるのを待つ |
| レコードは存在するが、チェックが依然として見つからないと報告する | ネガティブキャッシュ | SOAの値と最初のチェックの時刻を確認する | ネガティブキャッシュの時間を待つ |
| DMARCレポートにポリシーが表示されない | レコードが誤った名前にある | 名前が_dmarcで始まっているか確認する | _dmarc.yourdomain に移動する |
レコードレベルではなくヘッダーレベルの問題は、メッセージ自体で確認する方が簡単です。DNSが正しくなった後の認証結果の意味については、メールヘッダーの読み方をご覧ください。
繰り返し使える実践的な手順
- 特定する。プラットフォームが求める正確な名前とタイプを書き出します。
- 所在を確認する。NSルックアップで有効なネームサーバーを調べ、そのゾーンを編集していることを確認します。
- 入力する。相対ホスト名を使い、引用符を加えずに値を貼り付け、管理画面が必要とする場合に限り長い文字列を分割します。
- 読み戻す。権威サーバーに問い合わせ、結果を元の値と比較します。
- 整理する。重複、同じ名前の古いセレクタ、競合するレコードタイプを削除します。
- プロキシをオフにする。メール関連のレコードがDNS onlyに設定されていることを確認します。
- 賢く待つ。古いTTLとネガティブキャッシュ時間のうち、長い方を算出します。
- 検証する。プラットフォームのチェックを実行し、テストメッセージを送信します。公開すべき正確なレコード名と値は、MigoSMTPアカウントまたはAPIドキュメントで確認してください。
サポートに問い合わせる前のチェックリスト
- レコード名を権威ネームサーバーから読み戻し、プラットフォームが求めた名前と完全に一致している。
- 保存された名前に、ドメインのサフィックスが二重に含まれていない。
- 値に、貼り付けられた引用符、改行、長い鍵の内部のスペースがない。
- 長いTXT値が、文字列を連結したときに完全な形で存在している。
- その名前にSPFレコードが1つだけあり、ルックアップ数が上限以内である。
- CNAMEが他のレコードと名前を共有しておらず、apexにCNAMEがない。
- メール関連のすべてのレコードが、プロキシではなくDNS onlyに設定されている。
- 再確認する前に、古いTTLとネガティブキャッシュ時間を待った。
- 編集したゾーンが、NSレコードの指すゾーンである。
検証できないレコードでお困りですか?レコード名、公開した正確な値、権威ネームサーバーに対するdigクエリの出力をお送りください。違いを見つけるお手伝いをします。
参考資料と出典
よくある質問
DKIMレコードが長すぎると表示されるのはなぜですか?
DNSの1つの文字列(character-string)に入るのは最大255バイトで、2048ビットRSA公開鍵をbase64にするとそれより長くなります。レコード自体は複数の文字列を保持でき、受信側はそれらをスペースなしで連結します。管理画面によっては値を自動で分割してくれるもの、引用符で囲んだ断片の入力を求めるもの、長い値を受け付けないものがあります。お使いの画面の扱いを確認し、TXTルックアップで結果を検証してください。
TXTの値は引用符で囲むべきですか?
管理画面によって異なります。多くのWebフォームは引用符を自動で付加するため、自分で付けると値に引用符の文字がそのまま入り、レコードが解析できなくなります。ゾーンファイルエディタや一部のコマンドラインツールでは引用符が必要です。保存後にdigで読み戻し、引用符が二重になっていたりエスケープされていたりする場合は、ご自身で付けた引用符を外してください。
レコードが selector._domainkey.example.com.example.com になってしまったのはなぜですか?
管理画面は、ホスト欄に入力した内容の末尾に自動でドメイン名を付加します。完全な名前を入力するとドメインが二重に追加されます。自分のドメインより前の部分(selector._domainkey など)だけを入力するか、画面に表示されるヒントに従ってください。末尾のドットは名前が完結していることを示すと扱われることが多いものの、すべての画面がそう動作するわけではないため、ルックアップで確認してください。
ルートドメインにCNAMEを設定できますか?
標準のDNSでは設定できません。CNAMEは他のレコードと同じ名前に共存できず、ルートドメインにはSOAとNSレコードが必要だからです。プロバイダによっては、ルートでアドレスレコードを返すフラット化(flattening)やエイリアス機能を提供しています。Webトラフィックにはそれを利用できますが、メールに必要なルートのTXTやMXレコードの代わりには使わないでください。
SPFレコードが2つあります。本当に問題ですか?
はい、問題です。ドメインが公開できるSPFレコードは1つだけで、2つ以上見つけた受信側は、どちらかを選ぶのではなく永続エラー(permerror)を返します。メカニズムを1つのレコードにまとめてください。ルックアップ上限を超えずに行う方法は、1つのドメインで複数のベンダーを使う場合のガイドで解説しています。
TTLはどのくらいに設定すべきですか?
レコードの構築や変更中は300〜3600秒程度の短いTTL、安定したら数時間〜1日程度の長いTTLを使います。最適な値は、どれだけ素早くロールバックできるかと、ネームサーバーにかかる負荷とのトレードオフです。
レコードを修正したのに、チェックが失敗し続けるのはなぜですか?
考えられる原因は3つです。リゾルバがTTLの期限切れまで古い回答を保持している、ネガティブキャッシュの期限が切れるまで「見つからない」という回答を保持している、またはプラットフォームが参照する名前と異なる名前を確認している、のいずれかです。権威ネームサーバーに問い合わせて実際の状態を確認し、そのうえでキャッシュの期限切れを待ってください。
メール用のCNAMEをプロキシ経由にしてはいけないのはなぜですか?
DNSプロキシは、レコードの本来の参照先ではなく、プロキシ自身のアドレスで応答します。メールプラットフォームにはCNAMEの参照先または実際のサーバーアドレスが見える必要があるため、プロキシ経由のレコードは検証に失敗し、トラッキングやバウンス処理が機能しなくなることがあります。これらのレコードは「DNS only」に設定してください。
dig、nslookup、Webチェッカーのどれを信頼すべきですか?
何を問い合わせているかを理解していれば、どれも問題ありません。digとnslookupは問い合わせ先サーバーを指定できるため、公開の問題とキャッシュの問題を切り分ける鍵になります。Webチェッカーは通常、1つの場所から公開リゾルバ経由で問い合わせるため、手元の結果と食い違う場合は、単にキャッシュが異なるだけということがよくあります。