Diagnose and Fix Email Deliverability Problems¶
If your emails are landing in spam, the most common causes are misconfigured DNS records — specifically SPF, DKIM, and DMARC. The DNS Toolkit gives you the tools to diagnose your sending domain's mail configuration, validate individual addresses before sending, and block throwaway accounts at signup.
For full parameter and response schema details, see the API reference →
Two different problems, two different workflows¶
Your domain's email is going to spam — the sending domain has broken or missing SPF/DKIM/DMARC records. Use email-security and email-auth to find what's wrong.
Users are signing up with bad addresses — use email-validate to check reachability and disposable to block throwaway accounts.
Diagnose your sending domain¶
1. Get a quick summary with email-security¶
The email-security endpoint checks whether SPF, DKIM, and DMARC are present and syntactically valid. It returns a pass/warn/fail status for each and highlights the most likely issues.
from toolkitapi import DNS
with DNS(api_key="YOUR_KEY") as dns:
result = dns.email_security("yourdomain.com")
for check in result.checks:
icon = "✓" if check.status == "pass" else ("⚠" if check.status == "warn" else "✗")
print(f"{icon} {check.type}: {check.detail}")
curl "https://email.toolkitapi.io/v1/email/security?domain=yourdomain.com" \
-H "X-API-Key: YOUR_KEY"
const params = new URLSearchParams({ domain: "yourdomain.com" });
const r = await fetch(`https://email.toolkitapi.io/v1/email/security?${params}`, {
headers: { "X-API-Key": "YOUR_KEY" },
});
const data = await r.json();
data.checks.forEach(c => console.log(`${c.type}: ${c.status} — ${c.detail}`));
2. Read the raw records with email-auth¶
Once you know which records are failing, use email-auth to get their raw values. Compare these against what your mail provider told you to configure.
from toolkitapi import DNS
with DNS(api_key="YOUR_KEY") as dns:
result = dns.email_auth("yourdomain.com")
print(f"SPF: {result.spf or 'not found'}")
print(f"DMARC: {result.dmarc or 'not found'}")
if result.dkim:
for selector, record in result.dkim.items():
print(f"DKIM ({selector}): {record}")
curl "https://email.toolkitapi.io/v1/email/auth?domain=yourdomain.com" \
-H "X-API-Key: YOUR_KEY"
const params = new URLSearchParams({ domain: "yourdomain.com" });
const r = await fetch(`https://email.toolkitapi.io/v1/email/auth?${params}`, {
headers: { "X-API-Key": "YOUR_KEY" },
});
const data = await r.json();
console.log("SPF:", data.spf);
console.log("DMARC:", data.dmarc);
What to look for¶
| Missing record | What it means | Fix |
|---|---|---|
| No SPF | Receiving servers can't verify your senders | Add v=spf1 include:your-provider.com ~all TXT record |
SPF +all |
Anyone can send as you | Change to ~all (soft fail) or -all (hard fail) |
| No DMARC | No policy for spoofed mail | Add _dmarc TXT record, start with p=none for monitoring |
DMARC p=none |
You're monitoring only — mail still gets through | Harden to p=quarantine once you're confident |
| No DKIM | Messages lack cryptographic signatures | Enable DKIM in your mail provider and publish the CNAME/TXT |
Validate email addresses before sending¶
Use email-validate to check whether an address is syntactically valid and whether the MX records for its domain are reachable. This prevents bounces from malformed or unreachable addresses.
from toolkitapi import DNS
with DNS(api_key="YOUR_KEY") as dns:
result = dns.email_validate("[email protected]")
print(f"Valid syntax: {result.valid_syntax}")
print(f"MX reachable: {result.mx_found}")
print(f"Deliverable: {result.deliverable}")
curl "https://email.toolkitapi.io/v1/email/[email protected]" \
-H "X-API-Key: YOUR_KEY"
const params = new URLSearchParams({ email: "[email protected]" });
const r = await fetch(`https://email.toolkitapi.io/v1/email/validate?${params}`, {
headers: { "X-API-Key": "YOUR_KEY" },
});
const data = await r.json();
console.log(`Deliverable: ${data.deliverable}`);
Block disposable email addresses at signup¶
Disposable email services (Mailinator, TempMail, Guerrilla Mail, etc.) are used to bypass free trials, avoid re-engagement emails, and inflate signup numbers. The disposable endpoint checks whether an address or domain belongs to a known throwaway provider.
from toolkitapi import DNS
with DNS(api_key="YOUR_KEY") as dns:
result = dns.disposable("[email protected]")
if result.disposable:
print("Blocked: disposable email address")
else:
print("OK: not a known disposable provider")
curl "https://dns.toolkitapi.io/v1/[email protected]" \
-H "X-API-Key: YOUR_KEY"
const params = new URLSearchParams({ email: "[email protected]" });
const r = await fetch(`https://dns.toolkitapi.io/v1/disposable?${params}`, {
headers: { "X-API-Key": "YOUR_KEY" },
});
const data = await r.json();
if (data.disposable) console.log("Blocked: disposable");
A typical signup validation flow combines both checks:
from toolkitapi import DNS
def validate_signup_email(email: str) -> tuple[bool, str]:
with DNS(api_key="YOUR_KEY") as dns:
# Check disposable first — it's fast and doesn't cost extra lookups
disp = dns.disposable(email)
if disp.disposable:
return False, "Disposable email addresses are not allowed"
validate = dns.email_validate(email)
if not validate.valid_syntax:
return False, "Invalid email format"
if not validate.deliverable:
return False, "Email domain does not appear to accept mail"
return True, "OK"
ok, reason = validate_signup_email("[email protected]")
print(ok, reason)