Introduction
A signup form usually treats an email address as a delivery channel: send a verification link, wait for the click, then create the account. That proves the user controls an inbox. It does not prove the domain behind the inbox represents a legitimate company, a stable customer, or a low-risk identity.
Trial abuse, fake B2B accounts, coupon abuse, affiliate fraud, and low-quality lead capture often hide behind domains that look plausible at first glance. The pattern is familiar: a custom domain registered yesterday, privacy-shielded WHOIS data, no meaningful mail infrastructure, and just enough DNS to receive a verification email. A human reviewer can spot this after investigation. A product team needs the signal at signup time.
This is where an email domain reputation workflow helps. Extract the domain after the@ sign, query public domain intelligence, and turn the result into a risk score. WhoisJSON provides the building blocks through documented endpoints: the WHOIS API for registration age, registrar and EPP status, and the DNS Lookup API for MX, TXT, DMARC, BIMI, MTA-STS and TLS-RPT records. This article goes deeper than the short fraud-prevention section in WHOIS API use cases.
What Is Email Domain Reputation?
Email domain reputation is a risk assessment of the domain part of an email address, not the mailbox itself. For [email protected], the domain to inspect is example.com. The goal is not to decide whether the user is good or bad from one field. The goal is to separate normal business domains from domains that deserve more friction, review, or lower trust.
A real company domain usually has history. It was registered months or years ago, has stable nameservers, receives email through MX records, publishes at least some TXT-based mail policy, and does not carry suspicious EPP states. A disposable abuse domain often has the opposite profile: very recent creation, minimal DNS, hidden or missing ownership data, and no operational footprint beyond account creation.
Signals That Matter at Signup
The useful signals are simple, public, and fast enough to compute before or immediately after account creation.
| Signal | Endpoint | Why it matters |
|---|---|---|
| Domain registration age | /whois | A domain created in the last few days is more suspicious than a domain with years of history. |
age.isNewlyRegistered andage.isYoung | /whois | Pre-computed RDAP helper fields for recent-domain risk scoring. |
| Created and expiry dates | /whois | Short-lived or newly created domains deserve different treatment than established corporate domains. |
| EPP status | /whois | Hold, pending delete, or transfer-related states can reveal operational or abuse issues. |
| Registrar | /whois | Useful as context in your own internal model, especially when combined with past abuse history. |
| MX records | /nslookup | A business email domain should usually be configured to receive mail. |
| SPF and other TXT records | /nslookup | TXT records can reveal whether the domain is configured for legitimate outbound email. |
| DMARC | /nslookup | Missing or weak DMARC is not fraud by itself, but it lowers confidence for business identity checks. |
| MTA-STS and TLS-RPT | /nslookup | Stronger mail-security posture is a positive trust signal for mature organizations. |
The Swagger definition for/nslookup documents A, AAAA, CAA, CNAME, MX, NS, SOA, TXT, DMARC, BIMI, MTASTS, and TLSRPT in one response. That makes it practical to inspect mail posture without chaining many DNS calls yourself.
The API Contract You Need
WhoisJSON API requests use theAuthorization header with aTOKEN= prefix. The production base URL is:
https://whoisjson.com/api/v1For signup scoring, two endpoints usually cover the first version of the workflow.
curl "https://whoisjson.com/api/v1/whois?domain=example.com" \
-H "Authorization: TOKEN=YOUR_API_KEY"curl "https://whoisjson.com/api/v1/nslookup?domain=example.com" \
-H "Authorization: TOKEN=YOUR_API_KEY"Every API response includes aRemaining-Requests header according to the OpenAPI documentation. Track it in production, especially if signup scoring runs on the critical path. For retry behavior, see the guide on WHOIS API rate limits and 429 errors.
A Practical Signup Risk Score
Start with a transparent model that your support, sales, and security teams can understand. You can tune the weights later from your own abuse outcomes.
| Condition | Points | Reason |
|---|---|---|
age.isNewlyRegistered is true | +35 | Domain was created very recently. |
age.isYoung is true | +15 | Domain is relatively new but not necessarily high risk. |
| No MX records | +25 | Weak signal for a claimed business email domain. |
| No DMARC record | +10 | Lowers confidence in mature mail setup. |
| No SPF-like TXT record | +10 | Suggests minimal outbound mail posture. |
| EPP hold or pending delete signal | +20 | Domain may be suspended, disputed, or operationally unstable. |
| Fully redacted or absent owner contact data | +10 | Common and often legitimate, but useful as a secondary signal. |
The exact thresholds depend on your business. A developer tool with a generous free tier may tolerate less risk than an enterprise demo form where every lead is reviewed by sales anyway.
Python Example: Score an Email Domain
This example extracts the domain from an email address, calls WHOIS and DNS lookup, and returns a score with reasons. It only uses documented response fields from the WhoisJSON OpenAPI file.
import requests
API_KEY = "YOUR_API_KEY"
BASE_URL = "https://whoisjson.com/api/v1"
HEADERS = {"Authorization": f"TOKEN={API_KEY}"}
def email_domain(email: str) -> str:
if "@" not in email:
raise ValueError("Invalid email address")
return email.rsplit("@", 1)[1].strip().lower()
def parse_remaining_requests(value: str | None) -> int | None:
if value is None:
return None
try:
return int(value)
except ValueError:
return None
def get_json(path: str, domain: str) -> tuple[dict, int | None]:
response = requests.get(
f"{BASE_URL}{path}",
headers=HEADERS,
params={"domain": domain},
timeout=10,
)
response.raise_for_status()
remaining = parse_remaining_requests(response.headers.get("Remaining-Requests"))
return response.json(), remaining
def has_spf(txt_records: list) -> bool:
return any(str(record).lower().startswith("v=spf1") for record in txt_records or [])
def score_email_domain(email: str) -> dict:
domain = email_domain(email)
whois, whois_remaining = get_json("/whois", domain)
dns, dns_remaining = get_json("/nslookup", domain)
score = 0
reasons = []
age = whois.get("age") or {}
if age.get("isNewlyRegistered"):
score += 35
reasons.append("domain registered within 30 days")
elif age.get("isYoung"):
score += 15
reasons.append("domain registered within 365 days")
status_values = " ".join(whois.get("status") or []).lower()
if any(flag in status_values for flag in ["clienthold", "serverhold", "pendingdelete"]):
score += 20
reasons.append("domain has hold or pending delete status")
contacts = (whois.get("contacts") or {}).get("owner") or []
if not contacts:
score += 10
reasons.append("owner contact is absent or redacted")
mx_records = dns.get("MX") or []
if not mx_records:
score += 25
reasons.append("no MX records")
txt_records = dns.get("TXT") or []
if not has_spf(txt_records):
score += 10
reasons.append("no SPF-like TXT record")
dmarc_records = dns.get("DMARC") or []
if not dmarc_records:
score += 10
reasons.append("no DMARC record")
if score >= 75:
decision = "manual_review_or_block"
elif score >= 50:
decision = "step_up_verification"
elif score >= 25:
decision = "allow_with_monitoring"
else:
decision = "allow"
remaining_values = [
value for value in [whois_remaining, dns_remaining]
if value is not None
]
return {
"email": email,
"domain": domain,
"score": min(score, 100),
"decision": decision,
"reasons": reasons,
"remaining_requests": min(remaining_values) if remaining_values else None,
}
print(score_email_domain("[email protected]"))
Node.js Example: Signup Middleware
In a real SaaS app, you usually do not want to block the request thread forever. Run the check with explicit timeouts, store the score, and route the account into the right onboarding path.
const API_KEY = process.env.WHOISJSON_API_KEY;
const BASE_URL = 'https://whoisjson.com/api/v1';
function getEmailDomain(email) {
const parts = String(email).toLowerCase().trim().split('@');
if (parts.length !== 2 || !parts[1]) {
throw new Error('Invalid email address');
}
return parts[1];
}
function parseRemainingRequests(value) {
if (value === null) return null;
const parsed = Number.parseInt(value, 10);
return Number.isNaN(parsed) ? null : parsed;
}
async function fetchJson(path, domain) {
const url = new URL(`${BASE_URL}${path}`);
url.searchParams.set('domain', domain);
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 10000);
try {
const response = await fetch(url, {
headers: { Authorization: `TOKEN=${API_KEY}` },
signal: controller.signal
});
if (!response.ok) {
return { error: `HTTP ${response.status}` };
}
return {
data: await response.json(),
remainingRequests: parseRemainingRequests(response.headers.get('Remaining-Requests'))
};
} finally {
clearTimeout(timeout);
}
}
function hasSpf(txtRecords = []) {
return txtRecords.some((record) =>
String(record).toLowerCase().startsWith('v=spf1')
);
}
async function scoreSignupEmail(email) {
const domain = getEmailDomain(email);
const [whoisResult, dnsResult] = await Promise.all([
fetchJson('/whois', domain),
fetchJson('/nslookup', domain)
]);
if (whoisResult.error || dnsResult.error) {
return {
email,
domain,
score: 30,
decision: 'allow_with_monitoring',
reasons: ['domain intelligence lookup incomplete'],
remaining_requests: null
};
}
const whois = whoisResult.data;
const dns = dnsResult.data;
let score = 0;
const reasons = [];
const age = whois.age || {};
if (age.isNewlyRegistered) {
score += 35;
reasons.push('domain registered within 30 days');
} else if (age.isYoung) {
score += 15;
reasons.push('domain registered within 365 days');
}
const status = (whois.status || []).join(' ').toLowerCase();
if (status.includes('clienthold') || status.includes('serverhold') || status.includes('pendingdelete')) {
score += 20;
reasons.push('domain has hold or pending delete status');
}
const ownerContacts = (whois.contacts || {}).owner || [];
if (!ownerContacts.length) {
score += 10;
reasons.push('owner contact is absent or redacted');
}
if (!(dns.MX || []).length) {
score += 25;
reasons.push('no MX records');
}
if (!hasSpf(dns.TXT || [])) {
score += 10;
reasons.push('no SPF-like TXT record');
}
if (!(dns.DMARC || []).length) {
score += 10;
reasons.push('no DMARC record');
}
const decision =
score >= 75 ? 'manual_review_or_block' :
score >= 50 ? 'step_up_verification' :
score >= 25 ? 'allow_with_monitoring' :
'allow';
const remainingValues = [
whoisResult.remainingRequests,
dnsResult.remainingRequests
].filter((value) => value !== null);
return {
email,
domain,
score: Math.min(score, 100),
decision,
reasons,
remaining_requests: remainingValues.length
? Math.min(...remainingValues)
: null
};
}
module.exports = { scoreSignupEmail };
Avoiding False Positives
The most expensive mistake is treating a single technical signal as proof of fraud. New startups register new domains. Small businesses misconfigure DMARC. Some legitimate companies hide WHOIS contacts for privacy. A good onboarding model uses domain intelligence to decide the next step, not to replace judgment entirely.
- Do not block only because a domain is new. Combine age with MX, DMARC, user behavior, payment risk, IP reputation, and account velocity.
- Separate consumer email from business email. Gmail, Outlook, Yahoo and similar domains need a different policy than custom company domains.
- Keep an unknown state. If an API call times out or returns 429, mark the domain as unknown and retry later. Do not convert lookup failure into "safe" or "fraud".
- Review outcomes. Feed confirmed abuse and false positives back into your scoring weights.
If your workflow involves high-volume batches, use the patterns from the Bulk WHOIS lookup guide and avoid uncontrolled concurrency.
Where This Fits in Your Stack
Email domain reputation is not a replacement for email verification, CAPTCHA, device fingerprinting, payment risk, or abuse monitoring. It is a low-friction signal that arrives early enough to change the onboarding path.
| Signup event | Domain intelligence action | Product decision |
|---|---|---|
| Account created with business email | Score WHOIS age and DNS mail records | Allow or add step-up verification |
| Free trial started | Store score on account profile | Adjust quota, review, or sales routing |
| High usage in first hour | Re-check domain and account cohort | Trigger abuse review |
| Payment added | Compare risk score with billing identity | Reduce friction for trusted accounts |
For security-heavy workflows, connect this article with phishing domain detection and newly registered domain detection. For customer-domain onboarding, the DNS Lookup API guide explains broader DNS record handling.
FAQ
What is an email domain reputation API?
An email domain reputation API checks the domain part of an email address and returns risk signals such as registration age, EPP status, MX records, SPF, DMARC, and mail-security DNS records.
Can domain age detect signup fraud by itself?
No. Domain age is useful because many abuse domains are young, but legitimate companies also launch new domains. Combine it with DNS posture and account behavior.
Which endpoints are required?
Start with /whois and /nslookup. Add /ssl-cert-check when website activation, certificate issuer, SAN coverage, or certificate timing matters to your scoring model.
Should I run this before or after account creation?
For low-latency products, create the account first, run the score immediately, then decide the onboarding path. For high-risk products, run the check before granting quota or access to expensive workflows.
Conclusion
Signup fraud often looks like a normal email verification problem until you inspect the domain behind the address. WHOIS and DNS data give you a practical way to tell the difference between an established business domain and a newly registered, minimally configured identity.
The best first version is intentionally simple: extract the email domain, query WHOIS and DNS, compute a transparent score, and route users to allow, monitoring, step-up verification, manual review, or block. The score will improve as your own abuse data teaches you which signals matter most.
Build signup risk scoring with WhoisJSON
Use WHOIS, DNS, SSL, availability, subdomains and monitoring under one API key. Start with 1,000 free requests/month.