Spamhaus DBL · DQS-authenticated · 1ms cache hits

Spam-trap detection on every verify.

Authenticated Spamhaus DBL probes on every /v1/check call. Hits self-persist so future calls short-circuit at 1ms — and vrfymail returns the listing code so you can distinguish .2 spam from .4 phish and .5 malware. Most APIs flatten this to a boolean.

The verdict

A flag, a list, a code

When the domain is on Spamhaus DBL or our customer-consensus list, the verdict carries spam_trap: true plus a trap object naming the source and the listing code.

response.json
json
{
  "result": "undeliverable",
  "reason": "spam_trap",
  "reason_message": "This address is on a spam-trap list. Sending here will damage your sender reputation.",
  "spam_trap": true,
  "trap": {
    "listed": true,
    "lists": ["spamhaus_dbl"],
    "code": "127.0.1.2"
  },
  "disposable": false,
  "mx_found": true,
  "score": 0.0
}
DBL codes matter

Code matters. Most APIs lose it.

Spamhaus returns three distinct threat codes. A "this domain is a spam source" verdict means something different from "this domain hosts phishing." vrfymail returns the code so your handling can differ — block spam, flag phish, alert security on malware.

spamhaus-dbl-codes.txt
text
# Spamhaus DBL listing codes

127.0.1.2   spam        General spam source
127.0.1.4   phish       Phishing source
127.0.1.5   malware     Malware distribution source

# Most APIs flatten all three into spam_trap: true.
# vrfymail returns the code so you can distinguish severity.
How it works

Real-time probe, edge cache.

Every cache miss fires a DNS query against Spamhaus DBL via authenticated DQS. Spamhaus's free public-resolver tier is blocked by policy; the DQS-authenticated tier (free up to 100k queries/day) returns the listing code.

On a hit, we persist the domain to the domains table with is_spam_trap=1 and listing_code. The second customer asking about the same domain hits a D1 row in ~1ms — no Spamhaus query, no rate limit pressure, no double-bill on your end.

Customer-consensus promotion adds a second channel: ≥3 distinct customers POSTing hard_bounce or spam_complaint on the same domain within 30 days promotes it to is_spam_trap=1 globally. Catches traps Spamhaus hasn't seen yet.

Two sources, one verdict
  • spamhaus_dbl Spamhaus's authoritative list. ~150ms cold probe, 1ms cached.
  • customer_consensus Your bounces + spam complaints, aggregated. Catches new traps before they're DBL-listed.
  • trap.code Always returned when listed: 127.0.1.2 spam, .4 phish, .5 malware.
Pairs well with

Other signals on the same call

Every /v1/check request runs the DBL probe alongside disposable detection (269K+ domains), B2C strict-mode flags, and your per-customer bounce overlay. One call, every signal, 50ms p50 on cache hits.

Frequently asked

Spam-trap detection, answered

How does the Spamhaus DBL probe work on every verify?
Every /v1/check request that doesn't hit the per-customer cache fires a DNS query against Spamhaus DBL (Domain Block List) via their authenticated DQS (Data Query Service) endpoint. If the domain is listed, DBL returns a 127.0.1.X code naming the threat type — .2 spam, .4 phish, .5 malware. We persist every hit to our domains table so the second customer asking about the same domain short-circuits at 1ms (no DNS query, no DBL load, no double-bill).
What's the difference between disposable detection and spam-trap detection?
Disposable detection flags domains operated by temp-mail providers — users intentionally giving you a throwaway address. Spam-trap detection flags addresses that mail servers monitor to identify senders with bad list hygiene. Sending to a disposable hurts your engagement; sending to a spam-trap damages your sender reputation across every ESP you use. vrfymail returns both signals on every call.
Do I need my own Spamhaus DQS key?
No — vrfymail handles the DQS subscription. Spamhaus blocks public resolvers by policy (you can't just query DBL from a regular DNS lookup) and the authenticated tier requires a DQS key. We carry the DQS key on the verifier; your verdict includes the DBL result without you handling rate limits or key rotation.
What happens when a domain is on the customer-consensus list but not on Spamhaus?
It still returns spam_trap: true with trap.lists including customer_consensus. The consensus list comes from your bounce/complaint reports — if ≥3 distinct customers POST hard_bounce or spam_complaint on the same domain within 30 days, the domain promotes to is_spam_trap=1 across the database (free-mail providers excluded). Catches the traps Spamhaus hasn't seen yet.
Will the spam-trap check slow down my signup form?
First call on a never-seen domain: ~150-250ms cold path (DNS + DBL + MX probes run in parallel, never serialized). Every subsequent call on the same domain: ~1ms (database hit, no probe). Most production signup forms see 80%+ cache hits — the verifier learns your traffic shape after the first hour.

DBL probes, edge-cached. One verdict.

5,000 verifies/month free, no card. Paid plans start at $9/mo — see pricing.

Get my API key