【Node.js】dnsPromises.resolveMx()とは?基本的な使い方とプログラミング例

2025-05-16

dnsPromises.resolveMx() は、Node.js の dns モジュールが提供する非同期処理のための API の一つです。具体的には、指定されたドメイン名の MX (Mail Exchanger) レコード を解決(名前解決)し、その結果を Promise オブジェクトとして返します。

MX レコードとは?

MX レコードは、DNS (Domain Name System) のレコードの一種で、そのドメイン宛のメールをどのメールサーバが処理すべきかを指定するために使われます。MX レコードには、優先度(priority)とホスト名(exchange)が含まれており、優先度の数値が小さいほど優先度が高くなります。

dnsPromises.resolveMx() の動作

この関数を呼び出すと、Node.js は DNS サーバに対して指定されたドメイン名の MX レコードの問い合わせを行います。問い合わせが完了すると、Promise が以下のいずれかの状態で解決されます。

  • 失敗 (Rejected)
    MX レコードが見つからなかった場合や、DNS サーバとの通信でエラーが発生した場合、Promise は拒否され、エラーオブジェクトが渡されます。一般的なエラーとしては、dns.NODATA(レコードが見つからない)や dns.TIMEOUT(タイムアウト)などがあります。

  • 成功 (Resolved)
    MX レコードが見つかった場合、Promise は解決され、その結果として MX レコードの配列が渡されます。配列の各要素は、以下のプロパティを持つオブジェクトです。

    • priority: MX レコードの優先度を示す数値。
    • exchange: メールサーバのホスト名。

非同期処理 (Promises)

dnsPromises.resolveMx() は Promise を返すため、非同期処理として扱う必要があります。これは、DNS の名前解決に時間がかかる場合があるため、Node.js のイベントループをブロックしないようにするためです。Promise を扱う一般的な方法として、async/await 構文や .then().catch() メソッドを使用します。

使用例 (async/await を使用)

const dns = require('node:dns').promises;

async function resolveMxRecords(hostname) {
  try {
    const records = await dns.resolveMx(hostname);
    console.log(`MX レコード (${hostname}):`, records);
    records.forEach(record => {
      console.log(`  優先度: ${record.priority}, ホスト名: ${record.exchange}`);
    });
  } catch (err) {
    console.error(`MX レコードの解決に失敗 (${hostname}):`, err);
  }
}

resolveMxRecords('google.com');
resolveMxRecords('invalid-domain-that-does-not-exist.com');

使用例 (.then() と .catch() を使用)

const dns = require('node:dns').promises;

dns.resolveMx('example.com')
  .then((records) => {
    console.log('MX レコード (example.com):', records);
    records.forEach(record => {
      console.log(`  優先度: ${record.priority}, ホスト名: ${record.exchange}`);
    });
  })
  .catch((err) => {
    console.error('MX レコードの解決に失敗 (example.com):', err);
  });

dnsPromises.resolveMx() は、Node.js で指定されたドメイン名の MX レコードを非同期的に解決し、メールサーバの情報を取得するために使用する重要な関数です。Promise を利用することで、非同期処理を効率的に扱うことができます。



一般的なエラー

    • 原因
      指定されたドメイン名に MX レコードが存在しない場合に発生します。
    • トラブルシューティング
      • 指定したドメイン名が正しいかどうか再度確認してください。スペルミスなどがないか注意しましょう。
      • DNS ルックアップツール(例えば dignslookup)を使用して、実際にそのドメインに MX レコードが存在するかどうかを確認してみてください。
      • もし意図的に MX レコードが存在しないドメインに対してクエリを実行しているのであれば、このエラーは正常な動作です。
  1. dns.TIMEOUT: Query timed out after SERVFAIL (SERVFAIL 後にクエリがタイムアウトしました)

    • 原因
      DNS サーバへの問い合わせが時間内に応答を得られなかった場合に発生します。ネットワークの問題や、DNS サーバの負荷が高いなどが原因として考えられます。
    • トラブルシューティング
      • インターネット接続が正常であることを確認してください。
      • 一時的なネットワークの問題である可能性があるため、少し時間を置いて再度試してみてください。
      • 別の DNS サーバ(例えば Google Public DNS の 8.8.8.8 や Cloudflare DNS の 1.1.1.1)を使用するように設定を変更し、再度試してみるのも有効です。
      • ファイアウォールが DNS (通常 UDP/TCP ポート 53) の通信をブロックしていないか確認してください。
  2. dns.CONNREFUSED: Connection refused (接続が拒否されました)

    • 原因
      指定された DNS サーバへの接続が拒否された場合に発生します。DNS サーバがダウンしている、ファイアウォールでブロックされているなどの可能性があります。
    • トラブルシューティング
      • 指定している DNS サーバのアドレスが正しいか確認してください。
      • 別の DNS サーバを試してみてください。
      • ファイアウォールが DNS の通信をブロックしていないか確認してください。

トラブルシューティングの一般的なヒント

  • 再試行処理の実装
    一時的なネットワークの問題や DNS サーバの負荷が原因である場合、一定時間後に再試行するロジックを実装することも有効な場合があります。ただし、過度な再試行は DNS サーバに負荷をかける可能性があるため注意が必要です。
  • Promise のハンドリング
    async/await 構文を使用している場合は try...catch ブロックで、.then().catch() を使用している場合は .catch() メソッドでエラーを適切に捕捉し、ログ出力やエラー処理を行うようにしましょう。
  • DNS サーバの変更
    使用している DNS サーバに問題がある場合、別のパブリック DNS サーバ(Google、Cloudflare など)を試してみることで改善する場合があります。
  • ネットワーク環境の確認
    インターネット接続が安定しているか、ファイアウォールやルータの設定が DNS 通信を妨げていないかなどを確認してください。
  • DNS ルックアップツールの利用
    dig (Linux/macOS) や nslookup (Windows/macOS) などのコマンドラインツールを使用して、Node.js の外部から DNS の解決状況を確認することで、問題が Node.js のコードにあるのか、ネットワークや DNS サーバにあるのかを切り分けることができます。
  • エラーメッセージをよく読む
    エラーメッセージには、問題の原因の手がかりとなる情報が含まれています。


基本的な MX レコードの解決 (async/await を使用)

この例では、async/await 構文を使って指定されたドメイン名の MX レコードを非同期的に取得し、その結果をコンソールに出力します。

const dns = require('node:dns').promises;

async function resolveAndLogMx(hostname) {
  try {
    const records = await dns.resolveMx(hostname);
    console.log(`ドメイン: ${hostname}`);
    if (records.length > 0) {
      console.log('MX レコード:');
      records.forEach(record => {
        console.log(`  優先度: ${record.priority}, ホスト名: ${record.exchange}`);
      });
    } else {
      console.log('MX レコードは見つかりませんでした。');
    }
    console.log('---');
  } catch (err) {
    console.error(`MX レコードの解決に失敗 (${hostname}):`, err.message);
    console.log('---');
  }
}

// 解決したいドメイン名の配列
const domainsToResolve = ['google.com', 'example.com', 'invalid-domain-example.xyz'];

// 各ドメインに対して MX レコードを解決してログ出力
domainsToResolve.forEach(domain => {
  resolveAndLogMx(domain);
});

基本的な MX レコードの解決 (.then() と .catch() を使用)

こちらは、Promise の .then().catch() メソッドを使った同様の処理の例です。

const dns = require('node:dns').promises;

function resolveAndLogMxPromise(hostname) {
  dns.resolveMx(hostname)
    .then(records => {
      console.log(`ドメイン: ${hostname}`);
      if (records.length > 0) {
        console.log('MX レコード:');
        records.forEach(record => {
          console.log(`  優先度: ${record.priority}, ホスト名: ${record.exchange}`);
        });
      } else {
        console.log('MX レコードは見つかりませんでした。');
      }
      console.log('---');
    })
    .catch(err => {
      console.error(`MX レコードの解決に失敗 (${hostname}):`, err.message);
      console.log('---');
    });
}

// 解決したいドメイン名の配列
const domainsToResolvePromise = ['google.com', 'example.com', 'invalid-domain-example.xyz'];

// 各ドメインに対して MX レコードを解決してログ出力
domainsToResolvePromise.forEach(domain => {
  resolveAndLogMxPromise(domain);
});

特定のドメインの MX レコードを取得し、優先度でソートする

この例では、取得した MX レコードを優先度(priority)の昇順にソートして表示します。

const dns = require('node:dns').promises;

async function resolveAndSortMx(hostname) {
  try {
    const records = await dns.resolveMx(hostname);
    if (records.length > 0) {
      records.sort((a, b) => a.priority - b.priority); // 優先度で昇順ソート
      console.log(`ドメイン: ${hostname} (優先度でソート済み)`);
      console.log('MX レコード:');
      records.forEach(record => {
        console.log(`  優先度: ${record.priority}, ホスト名: ${record.exchange}`);
      });
    } else {
      console.log(`ドメイン: ${hostname} に MX レコードは見つかりませんでした。`);
    }
    console.log('---');
  } catch (err) {
    console.error(`MX レコードの解決に失敗 (${hostname}):`, err.message);
    console.log('---');
  }
}

resolveAndSortMx('google.com');

エラー処理の例 (特定の DNS エラーを捕捉)

この例では、MX レコードが見つからない場合のエラー (dns.NODATA) を特定して処理しています。

const dns = require('node:dns').promises;
const dnsConstants = require('node:dns').constants;

async function resolveMxWithErrorHandling(hostname) {
  try {
    const records = await dns.resolveMx(hostname);
    console.log(`ドメイン: ${hostname}`);
    console.log('MX レコード:', records);
    console.log('---');
  } catch (err) {
    if (err.code === dnsConstants.NODATA) {
      console.log(`ドメイン: ${hostname} に MX レコードは見つかりませんでした。`);
      console.log('---');
    } else {
      console.error(`MX レコードの解決に失敗 (${hostname}):`, err.message);
      console.log('---');
    }
  }
}

resolveMxWithErrorHandling('example.com');
resolveMxWithErrorHandling('no-mx-record.example'); // MX レコードが存在しない可能性のあるドメイン


コールバックベースの dns.resolveMx()

Promise ベースの dnsPromises.resolveMx() が導入される以前から存在していた、コールバック関数を使用する非同期 API です。

const dns = require('node:dns');

dns.resolveMx('example.com', (err, records) => {
  if (err) {
    console.error('MX レコードの解決に失敗しました:', err);
    return;
  }
  console.log('example.com の MX レコード:');
  if (records && records.length > 0) {
    records.forEach(record => {
      console.log(`  優先度: ${record.priority}, ホスト名: ${record.exchange}`);
    });
  } else {
    console.log('MX レコードは見つかりませんでした。');
  }
});

dns.resolveMx('invalid-domain-that-does-not-exist.com', (err, records) => {
  if (err) {
    console.error('MX レコードの解決に失敗しました:', err);
    return;
  }
  console.log('invalid-domain-that-does-not-exist.com の MX レコード:');
  // ... 結果の処理 ...
});
  • 特徴
    • コールバック関数を引数として渡します。このコールバック関数は、エラーが発生した場合の err オブジェクトと、成功した場合の結果(この場合は MX レコードの配列)を受け取ります。
    • 非同期処理の結果を扱うために、コールバック関数内で処理を記述する必要があります。
    • Promise ベースの API に比べて、非同期処理のフローを管理するのがやや複雑になる場合があります(特に複数の非同期処理が連鎖する場合など)。

同期的な dns.resolveMxSync() (非推奨)

dns モジュールには、同期的に DNS ルックアップを行う dns.resolveMxSync() というメソッドも存在します。

const dns = require('node:dns');

try {
  const records = dns.resolveMxSync('google.com');
  console.log('google.com の MX レコード (同期):', records);
} catch (err) {
  console.error('MX レコードの同期的な解決に失敗しました:', err);
}

try {
  const records = dns.resolveMxSync('another-invalid-domain.com');
  console.log('another-invalid-domain.com の MX レコード (同期):', records);
} catch (err) {
  console.error('MX レコードの同期的な解決に失敗しました:', err);
}
  • 特徴
    • Sync というサフィックスが付いている通り、このメソッドは同期的に実行されます。つまり、DNS ルックアップが完了するまで Node.js のイベントループがブロックされます。
    • 成功した場合は結果を直接返し、エラーが発生した場合は try...catch ブロックで捕捉できる例外をスローします。
    • 注意
      同期的な DNS ルックアップは、アプリケーションの応答性を損なう可能性があるため、一般的には推奨されません。特に、ネットワークの遅延が大きい場合や、DNS サーバの応答が遅い場合には、アプリケーションがフリーズしたように見えることがあります。
  • dns.resolveMxSync() は、特別な理由がない限り避けるべきです。 メインスレッドをブロックするため、パフォーマンスに悪影響を与える可能性が高いです。例えば、コマンドラインツールのような、短い処理時間で完了することが保証されている場合に限って、限定的に使用されることがあります。
  • 既存のコードベースでコールバック関数が広く使われている場合
    dns.resolveMx() を使用することも選択肢の一つですが、可能であれば Promise ベースの API への移行を検討する価値があります。
  • 新規開発や、よりモダンな非同期処理を取り入れたい場合
    dnsPromises.resolveMx() を使用することを強く推奨します。Promise ベースの API は、async/await 構文と組み合わせることで、非同期処理をよりシンプルで読みやすいコードで記述できます。また、Promise はエラーハンドリングや非同期処理の連鎖をより容易にします。