Email Health Monitoring Through Nova Uptime's Public API: Developer Integration Guide
Build custom email health monitoring into your platform using Nova Uptime's REST API. Complete guide with code examples, rate limits, and production patterns.
Why Use Nova Uptime's API for Email Health Monitoring?#
If you manage customer domains (SaaS platform, hosting provider, agency), you need to programmatically check email health across all of them.
Three Approaches:
- Manual: Check each domain in Nova Uptime's dashboard. Not scalable.
- WHOIS Queries: Write custom DKIM/SPF/DMARC parsing. Complex, unreliable.
- Nova Uptime Public API: REST API that handles all complexity. Scalable, reliable, maintained.
This guide covers the API approach.
API Overview#
Base URL: https://api.novauptime.com/api/v1
Authentication: X-API-Key header
Rate Limits: 50 requests/hour for free tier, 1,000/hour for paid
Response Format:
{
"success": true,
"data": { ... },
"message": "Optional message"
}
Step 1: Generate Your API Key#
- Log into go.novauptime.com
- Settings → API Keys
- Click "Generate New Key"
- Copy the 20-character key (e.g.,
abc123def456ghi789jk) - Store securely (don't commit to git!)
Environment Variable:
export NOVAUPTIME_API_KEY="abc123def456ghi789jk"
Step 2: Check Email Health for a Domain#
Endpoint: GET /domains/{domain}/email-health
Example Request:
curl -H "X-API-Key: abc123def456ghi789jk" \
https://api.novauptime.com/api/v1/domains/example.com/email-health
Response:
{
"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"
}
]
}
}
Real-World Use Cases#
Use Case 1: Agency Dashboard#
You're an agency managing 100+ client websites. You want to show each client their email health in your dashboard.
Implementation:
// 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);
});
Use Case 2: Automated Email Health Scoring#
Grade all customer domains and alert on degradation.
Implementation:
// 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()
});
}
}
Use Case 3: Bulk Domain Audit#
You acquired a competitor. 50 new customer domains. You want email health status for all.
Implementation:
// 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 Patterns for Production#
Pattern 1: Caching with Expiration#
Don't call the API every request. Cache results locally.
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;
}
Pattern 2: Rate Limit Handling#
Nova Uptime API has rate limits. Handle gracefully.
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));
}
}
}
Pattern 3: Batch Processing#
When checking 100+ domains, batch requests efficiently.
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;
}
Pattern 4: Storing Results Locally#
Store email health results in your own database for historical tracking.
// 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;
}
Pattern 5: Alerting on Changes#
Track changes and alert team when something breaks.
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")}
`
});
}
}
Error Handling#
Common Error Scenarios:
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;
}
}
}
Frontend Integration#
React Component Example#
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 Documentation Reference#
Base URL: https://api.novauptime.com/api/v1
Endpoints:
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
Best Practices#
- Cache aggressively: Email health doesn't change frequently. Cache for 1-24 hours.
- Batch requests: Check 10 domains concurrently, not 1 at a time.
- Handle errors gracefully: Network issues happen. Retry with exponential backoff.
- Monitor the API: Track your API usage. If approaching rate limit, cache longer.
- Secure your API key: Never commit to git. Use environment variables.
- Test rate limits: Simulate high volume before deploying to production.
Summary: API Integration Checklist#
- ✅ Generate and secure API key
- ✅ Implement basic email health check
- ✅ Add caching layer (Redis or in-memory)
- ✅ Implement rate limit handling
- ✅ Add error handling for common failures
- ✅ Test with your actual domain
- ✅ Build frontend component to display results
- ✅ Set up alerting for score changes
- ✅ Document API key management in team wiki
- ✅ Monitor API usage and quota
Get Started Today#
The Nova Uptime public API is available on the free tier. Generate your first API key in Settings and start integrating email health checks into your platform.
For detailed API reference, visit the Nova Uptime API documentation.
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 FreeRelated Articles
How to Integrate Uptime Monitoring Into Your App With an API
A developer guide to integrating website uptime monitoring using Nova Uptime's REST API. Includes authentication, endpoints, code examples, and best practices.
Best Free Email Health Check Tools in 2026: A Comparison
Compared 8 free email health checkers: Nova Uptime, MXToolbox, DMARCian, EasyDMARC, Postmark, Mailtrap, Sender Score, ZeroBounce. SPF/DKIM/DMARC + blacklists.
Domain Health Check: A Complete Free Audit (DNS + SSL + Email + Uptime)
Run a complete free domain health audit in 5 minutes: DNS, SSL, email auth (SPF/DKIM/DMARC), blacklists, and uptime. Step-by-step checklist included.