Nova Uptime
ガイドapiemail-healthdeveloper

Nova UptimeのパブリックAPIで実現するメール配信ヘルス監視:開発者向け統合ガイド

Nova UptimeのREST APIを使って、独自プラットフォームにメール配信ヘルス監視を組み込みましょう。コード例、レート制限、本番環境向けパターンを網羅した完全ガイドです。 — Nova Uptimeはアップタイム、SSL、メール健全性、リンク変更を1つのダッシュボードで監視します。

SN
Sumit Nova Uptime
2026年2月28日 · 11 min read
Share:

なぜメール配信ヘルス監視にNova UptimeのAPIを使うのか?#

顧客のドメインを管理している方(SaaSプラットフォーム、ホスティングプロバイダー、代理店など)であれば、すべてのドメインのメール配信ヘルスをプログラム的にチェックする必要があります。

3つのアプローチ:

  1. 手動: Nova Uptimeのダッシュボードで各ドメインを個別にチェック。スケールしません。
  2. WHOISクエリ: 独自にDKIM/SPF/DMARCのパース処理を実装。複雑で信頼性に欠けます。
  3. Nova UptimeのパブリックAPI: 複雑な処理をすべて引き受けるREST API。スケーラブルで信頼性が高く、メンテナンスも継続的に行われています。

本ガイドではAPIアプローチを取り上げます。

API概要#

ベースURL: https://api.novauptime.com/api/v1

認証方式: X-API-Keyヘッダー

レート制限: 無料プランは50リクエスト/時、有料プランは1,000リクエスト/時

レスポンス形式:

{
  "success": true,
  "data": { ... },
  "message": "Optional message"
}

ステップ1: APIキーを発行する#

  1. go.novauptime.comにログイン
  2. 設定 → APIキー
  3. 「Generate New Key」をクリック
  4. 20文字のキーをコピー(例: abc123def456ghi789jk)
  5. 安全に保管(gitにコミットしないでください!)

環境変数:

export NOVAUPTIME_API_KEY="abc123def456ghi789jk"

ステップ2: ドメインのメール配信ヘルスをチェックする#

エンドポイント: GET /domains/{domain}/email-health

リクエスト例:

curl -H "X-API-Key: abc123def456ghi789jk" \
  https://api.novauptime.com/api/v1/domains/example.com/email-health

レスポンス:

{
  "success": true,
  "data": {
    "domain": "example.com",
    "score": 92,
    "grade": "A",
    "timestamp": "2026-02-20T10:30:00Z",
    "records": {
      "mx": {
        "status": "configured",
        "value": "mail.example.com"
      },
      "spf": {
        "status": "configured",
        "value": "v=spf1 include:sendgrid.net -all",
        "lookups": 4
      },
      "dkim": {
        "status": "configured",
        "selectors": ["s1", "s2"],
        "configured_count": 2
      },
      "dmarc": {
        "status": "configured",
        "policy": "reject"
      },
      "blacklist": {
        "status": "clean",
        "checked_against": 4,
        "listed_on": 0
      }
    },
    "recommendations": [
      {
        "type": "warning",
        "message": "SPF record has 4 lookups (limit is 10). Consider consolidating includes.",
        "action": "Use SPF flattening service or consolidate email providers"
      }
    ]
  }
}

実際のユースケース

ユースケース1: 代理店ダッシュボード#

100以上のクライアントのウェブサイトを管理する代理店として、各クライアントに自社ダッシュボード上でメール配信ヘルスを表示したい場合があります。

実装例:

// Express.js route to fetch email health
app.get("/client/:clientId/email-health", async (req, res) => {
  const clientId = req.params.clientId;

  // Get client's domain from database
  const client = await Client.findById(clientId);
  const domain = client.primaryDomain;

  // Fetch email health from Nova Uptime
  const response = await fetch(
    `https://api.novauptime.com/api/v1/domains/${domain}/email-health`,
    {
      headers: { "X-API-Key": process.env.NOVAUPTIME_API_KEY }
    }
  );

  const emailHealth = await response.json();

  // Return to frontend
  res.json(emailHealth.data);
});

ユースケース2: メール配信ヘルスの自動スコアリング#

すべての顧客ドメインを採点し、悪化を検知したらアラートを送ります。

実装例:

// Cron job: Check all domains daily
async function dailyEmailHealthAudit() {
  const domains = await Domain.find();

  for (const domain of domains) {
    // Fetch current score
    const current = await fetchEmailHealth(domain.name);

    // Compare to previous day
    const previous = await EmailHealthHistory.findLatest(domain.name);

    if (current.data.score < previous.score - 5) {
      // Score dropped >5 points, alert
      await sendSlackAlert({
        domain: domain.name,
        oldScore: previous.score,
        newScore: current.data.score,
        change: current.data.score - previous.score
      });
    }

    // Store history
    await EmailHealthHistory.create({
      domain: domain.name,
      score: current.data.score,
      timestamp: new Date()
    });
  }
}

ユースケース3: 一括ドメイン監査#

競合他社を買収し、新たに50のクライアントドメインが加わったとします。すべてのメール配信ヘルス状態を把握したい場合のパターンです。

実装例:

// Fetch email health for 50 domains
async function auditAcquiredDomains(acquiredDomains) {
  const results = [];

  // Fetch with concurrency limit (5 at a time)
  for (const domain of acquiredDomains) {
    const health = await fetchEmailHealth(domain);
    results.push({
      domain,
      score: health.data.score,
      grade: health.data.grade,
      issues: health.data.recommendations
    });
  }

  // Export to CSV
  const csv = convertToCSV(results);
  fs.writeFileSync("email-health-audit.csv", csv);

  // Summary: 40 domains healthy, 10 need fixes
  console.log(`Healthy: ${results.filter(r => r.score > 80).length}`);
  console.log(`Need fixes: ${results.filter(r => r.score < 80).length}`);
}

本番環境向けAPIパターン#

パターン1: 有効期限付きキャッシュ#

リクエストのたびにAPIを呼び出すのは避け、結果はローカルでキャッシュしましょう。

const redis = require("redis");
const client = redis.createClient();

async function getEmailHealthCached(domain, maxAge = 3600) {
  // Try cache first
  const cached = await client.get(`email-health:${domain}`);
  if (cached) {
    return JSON.parse(cached);
  }

  // Cache miss, fetch from API
  const health = await fetchEmailHealth(domain);

  // Store in cache for 1 hour
  await client.setex(
    `email-health:${domain}`,
    maxAge,
    JSON.stringify(health.data)
  );

  return health.data;
}

パターン2: レート制限への対応#

Nova UptimeのAPIにはレート制限があります。適切にハンドリングしましょう。

async function fetchWithRetry(domain, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      const response = await fetch(
        `https://api.novauptime.com/api/v1/domains/${domain}/email-health`,
        {
          headers: { "X-API-Key": process.env.NOVAUPTIME_API_KEY },
          timeout: 10000
        }
      );

      if (response.status === 429) {
        // Rate limited, wait before retry
        const retryAfter = response.headers.get("Retry-After") || (2 ** i);
        console.log(`Rate limited. Retrying in ${retryAfter}s`);
        await new Promise(r => setTimeout(r, retryAfter * 1000));
        continue;
      }

      if (!response.ok) throw new Error(`HTTP ${response.status}`);

      return await response.json();
    } catch (error) {
      if (i === maxRetries - 1) throw error;
      console.log(`Attempt ${i + 1} failed, retrying...`);
      await new Promise(r => setTimeout(r, (2 ** i) * 1000));
    }
  }
}

パターン3: バッチ処理#

100以上のドメインをチェックする場合は、リクエストを効率的にバッチ化しましょう。

async function batchEmailHealthCheck(domains) {
  const batchSize = 10; // 10 concurrent requests
  const results = [];

  for (let i = 0; i < domains.length; i += batchSize) {
    const batch = domains.slice(i, i + batchSize);

    // Process batch concurrently
    const batchResults = await Promise.all(
      batch.map(domain => fetchEmailHealth(domain))
    );

    results.push(...batchResults);

    // Log progress
    console.log(`Processed ${Math.min(i + batchSize, domains.length)}/${domains.length}`);
  }

  return results;
}

パターン4: 結果をローカルに保存する#

メール配信ヘルスの結果を自社のデータベースに保存し、履歴として追跡します。

// Database model
const EmailHealthSchema = {
  domain: String,
  score: Number,
  grade: String,
  records: {
    mx: Object,
    spf: Object,
    dkim: Object,
    dmarc: Object,
    blacklist: Object
  },
  timestamp: Date,
  createdAt: Date
};

async function storeEmailHealth(domain) {
  const health = await fetchEmailHealth(domain);

  // Store in DB
  const record = new EmailHealthLog({
    domain,
    score: health.data.score,
    grade: health.data.grade,
    records: health.data.records,
    timestamp: new Date(health.data.timestamp),
    createdAt: new Date()
  });

  await record.save();

  return record;
}

パターン5: 変化を検知してアラート#

変化を追跡し、問題が発生したらチームへ通知します。

async function monitorEmailHealth(domain) {
  const current = await getEmailHealthCached(domain);
  const previous = await EmailHealthLog.findLatest(domain);

  if (!previous) {
    // First check, just store it
    await storeEmailHealth(domain);
    return;
  }

  // Detect changes
  const scoreChange = current.score - previous.score;

  if (scoreChange < -10) {
    // Major degradation
    await alertSlack({
      channel: "#email-alerts",
      message: `
        ${domain}: Email health degraded
        Previous: ${previous.score} (${previous.grade})
        Current: ${current.score} (${current.grade})
        Change: ${scoreChange < 0 ? "" : "+"}${scoreChange}

        Issues: ${current.recommendations.map(r => r.message).join("\n")}
      `
    });
  }
}

エラーハンドリング

よくあるエラーシナリオ:

async function robustEmailHealthCheck(domain) {
  try {
    const health = await fetchWithRetry(domain);
    return health.data;
  } catch (error) {
    if (error.code === "ENOTFOUND") {
      // Domain doesn't exist
      console.error(`Domain ${domain} not found`);
      return null;
    } else if (error.statusCode === 401) {
      // Invalid API key
      console.error("Invalid Nova Uptime API key");
      return null;
    } else if (error.statusCode === 429) {
      // Rate limited (even after retries)
      console.error("Rate limit exceeded");
      return null;
    } else {
      // Unknown error
      console.error(`Error checking ${domain}: ${error.message}`);
      return null;
    }
  }
}

フロントエンドとの統合

Reactコンポーネント例#

import { useState, useEffect } from 'react';

function EmailHealthCard({ domain }) {
  const [health, setHealth] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    async function fetchHealth() {
      try {
        const response = await fetch(`/api/email-health/${domain}`);
        const data = await response.json();
        setHealth(data);
      } catch (err) {
        setError(err.message);
      } finally {
        setLoading(false);
      }
    }

    fetchHealth();
  }, [domain]);

  if (loading) return <div>Loading...</div>;
  if (error) return <div>Error: {error}</div>;

  return (
    <div className="email-health-card">
      <h3>{domain}</h3>
      <div className={`score score-${health.grade}`}>
        {health.score}/100 ({health.grade})
      </div>

      <div className="records">
        {Object.entries(health.records).map(([key, value]) => (
          <div key={key} className={`record ${value.status}`}>
            <strong>{key.toUpperCase()}</strong>: {value.status}
          </div>
        ))}
      </div>

      {health.recommendations.length > 0 && (
        <div className="recommendations">
          <h4>Recommendations:</h4>
          <ul>
            {health.recommendations.map((rec, i) => (
              <li key={i} className={rec.type}>
                {rec.message}
              </li>
            ))}
          </ul>
        </div>
      )}
    </div>
  );
}

APIドキュメントリファレンス#

ベースURL: https://api.novauptime.com/api/v1

エンドポイント:

GET /domains/{domain}/email-health
  → Check email health for domain
  → Rate limit: 50/hour (free), 1000/hour (paid)
  → Response: Email health score, grade, records, recommendations

GET /domains/{domain}/incidents
  → Get last 20 downtime incidents
  → Optional param: limit, offset

GET /domains/{domain}/history
  → Get check history (configurable hours, max 720h)
  → Optional params: hours (default 168), limit (default 500)

GET /domains
  → List user's domains (paginated, max 50/page)
  → Optional params: page, limit

ベストプラクティス

  1. 積極的にキャッシュする: メール配信ヘルスは頻繁には変化しません。1〜24時間キャッシュしましょう。
  2. リクエストをバッチ化する: 1件ずつではなく、10ドメインを並列でチェックします。
  3. エラーを丁寧にハンドリングする: ネットワーク障害は起こります。指数バックオフでリトライしましょう。
  4. APIを監視する: API使用量を追跡しましょう。レート制限に近づいたらキャッシュ期間を延ばします。
  5. APIキーを安全に保管する: gitにコミットしないでください。環境変数を使いましょう。
  6. レート制限をテストする: 本番投入前に高負荷をシミュレーションしましょう。

まとめ: API統合チェックリスト#

  • ✅ APIキーを発行し、安全に保管する
  • ✅ 基本的なメール配信ヘルスチェックを実装する
  • ✅ キャッシュ層を追加する(Redisまたはインメモリ)
  • ✅ レート制限のハンドリングを実装する
  • ✅ よくある失敗パターンに対するエラーハンドリングを追加する
  • ✅ 自社の実ドメインでテストする
  • ✅ 結果を表示するフロントエンドコンポーネントを構築する
  • ✅ スコア変化に対するアラートを設定する
  • ✅ チームのwikiにAPIキー管理方法を文書化する
  • ✅ API使用量とクォータを監視する

今すぐ始めましょう

Nova UptimeのパブリックAPIは無料プランから利用できます。設定画面で最初のAPIキーを発行し、メール配信ヘルスチェックを自社プラットフォームに統合してみてください。

詳細なAPIリファレンスについては、Nova UptimeのAPIドキュメントをご覧ください。

Monitor Your Website Before It Goes Down

Get uptime monitoring, SSL tracking, domain expiry alerts, and email health checks. Free plan — no credit card required.

Start Monitoring Free

関連記事