Risk signals
Every Spaw answer that carries a risk score lists the signals that fired in risk_signals, each with the weight applied and the dataset it was read from, and the weights sum to risk_score, capped at 100. The score is arithmetic, not a model. Each product keeps its own list, and the same name can carry a different weight on each: disposable is +80 on an email answer and +70 on a phone one. So each list has its own pages.
- Email · 21 signals, one page each at /docs/signals/{signal}
- Phone · 18 signals, one page each at /docs/signals/phone/{signal}
- IP and address · listed in their guides, no pages yet
Email signals
Every deliverable or risky email answer lists its signals; an undeliverable verdict is always 100 with an empty list. Four rules bind the list: catch_all_gateway replaces catch_all behind a security gateway, young_domain and new_domain are exclusive, no_reply is added on top of role, and relay cancels disposable. The decision is your sending policy. Each signal has its own page with the full explanation, an example and what to do with the input.
| signal | weight | reads | dataset | meaning |
|---|---|---|---|---|
| disposable | +80 | disposable | disposable-domains | The mailbox lives at a disposable-address service, so it exists to be thrown away; this is the largest weight there is. reason: disposable |
| parked_domain | +60 | parked | parking-nameservers | The domain is parked or for sale and still accepts mail, so whoever collects that mail is not your customer. reason: parked_domain |
| likely_typo | +60 | did_you_mean | typo-domains | The domain is on the curated map of misspellings that resolve and run catch-alls to harvest misdirected mail, and did_you_mean carries the intended address. reason: likely_typo |
| mx_blocklisted | +60 | mx_blocklisted | threat-blocklists | At least one MX host resolves into a network on the threat blocklists the IP product installs — Spamhaus DROP and ASN-DROP, abuse.ch Feodo Tracker — a burner signal no domain list has caught yet. reason: mx_blocklisted |
| implicit_mx | +30 | mx_implicit | live-dns | The domain publishes no MX record, so mail would fall back to its own address under RFC 5321; such web-only domains rarely accept mail and are never probed. reason: implicit_mx |
| role | +30 | role | role-addresses | info@, support@, billing@ and the rest of the open role-address list name a function, so the inbox may be shared, filtered or unread. reason: role, no_reply |
| catch_all | +30 | catch_all | mailbox-smtp | The handshake said yes to a recipient that cannot exist, so a yes for this one proves nothing; mailbox_confidence estimates the rest. reason: catch_all |
| young_domain | +30 | domain_age_days | rdap-registration | The registry's RDAP record puts the registration less than 30 days back — the age of a domain set up for one campaign. |
| recycled_mailbox | +30 | previously_invalid | mailbox-history | A definitive no-such-mailbox was recorded for the address earlier and the mailbox answers now — the shape of a recycled address, the spam-trap kind included. reason: recycled_mailbox |
| mailbox_full | +20 | smtp_reason | mailbox-smtp | The handshake found the mailbox and was told it is full, so mail will bounce until the owner clears it. reason: mailbox_full |
| gibberish | +20 | is_gibberish | local-part-analysis | Six letters or more with no vowel, or six consonants in a row, and nothing the bundled name lists recognise — deliberately conservative. |
| generated | +20 | looks_generated | local-part-analysis | A hex string, a UUID, a base64-looking run, one or two letters before four digits, a word before six digits, or a placeholder word such as test or asdf. |
| no_reply | +20 | role_type | role-types | noreply, donotreply, mailer-daemon and their kin are addresses mail is sent from and never read at; this weight is added on top of the role weight. reason: no_reply |
| widely_seen | +20 | widely_seen | lookup-velocity | At least three other Spaw accounts looked the address up in the last 24 hours — an address hitting many signup forms at once. |
| catch_all_gateway | +15 | mx_provider_type | mailbox-smtp | The domain accepts every address but its mail runs through Proofpoint, Mimecast or Barracuda, where accepting every recipient is the gateway's design; this lighter weight takes the place of the catch-all one. reason: catch_all |
| new_domain | +10 | domain_age_days | rdap-registration | The registration is between 30 and 179 days old — past its first month, not yet an established domain. |
| no_spf | +10 | has_spf | live-dns | The domain has no SPF policy in DNS, which a maintained business domain almost always has; free providers are exempt because theirs is known. |
| unverified | +10 | smtp_checked | mailbox-smtp | The handshake ran and did not settle the mailbox — greylisting, a timeout, an unreachable server, a partner outage — so smtp_checked is false and the verdict is risky. reason: unverified |
| expiring_domain | +10 | domain_expires_at | rdap-registration | RDAP puts the registration's end inside the next 30 days — a domain that may be about to lapse. |
| alias | +5 | is_alias | local-part-analysis | mia+promo@ is the same inbox as mia@ under a disposable label — a favourite of signup-bonus farmers, and the reason to dedupe on normalized_email. |
| relay | +5 | is_relay | forwarding-services | Firefox Relay, SimpleLogin, Addy.io, DuckDuckGo Email Protection and their kind deliver to a real person's mailbox under a name they control; the identity is withheld, not the mailbox. |
Phone signals
Every valid phone answer lists its signals; an invalid number has no score and lists nothing. disposable and disposable_stale never fire together, disposable_range fires only for a number the lists do not carry, and range_burst and numbers_per_client come from nothing but your own account’s lookups. A dataset marked “regulator table” is whichever country’s allocation table answered, named in the answer. The decision is your SMS policy.
| signal | weight | reads · dataset | meaning |
|---|---|---|---|
| fictional | +80 | is_fictionalfictional-ranges | the number sits in a range reserved for fiction blocked by the default SMS policy |
| disposable | +70 | is_disposabledisposable_seen_atdisposable-phone-numbers | published by an SMS-receiving website blocked by the default SMS policy |
| disposable_stale | +40 | is_disposabledisposable_seen_atdisposable-phone-numbers | published by an SMS-receiving website, but not recently |
| reported_abuse | +60 | no field of its owndelivery-feedback | your own account reported abuse for the number blocked by the default SMS policy |
| reported_undelivered | +50 | no field of its owndelivery-feedback | your own latest report for the number was a failed delivery |
| reported_abuse_widely | +40 | no field of its owndelivery-feedback | three or more accounts reported abuse for the number blocked by the default SMS policy |
| premium_rate | +60 | line_typelibphonenumber | a premium-rate number blocked by the default SMS policy |
| reserved_block | +40 | block_statusregulator table | the regulator's table marks the block reserved |
| virtual | +40 | is_virtualregulator table | the block is held by a virtual-number wholesaler or VoIP provider |
| range_burst | +40 | range_seen_by_youaccount-velocity | your account looked up several numbers in the same range within the window |
| voip | +30 | line_typelibphonenumber | the numbering plan types the number as VoIP |
| pager | +30 | line_typelibphonenumber | the numbering plan types the number as a pager |
| digit_pattern | +30 | e164digit-pattern | repeated or sequential subscriber digits |
| numbers_per_client | +30 | client_velocityaccount-velocity | one client address tried several numbers within the window |
| disposable_range | +30 | no field of its owndisposable-phone-numbers | not listed, but in a range crowded with SMS-receiving numbers |
| international_network | +30 | calling_codelibphonenumber | an international network or satellite number |
| shared_cost | +20 | line_typelibphonenumber | a shared-cost number |
| reported_unwanted_calls | +20 | complaints_90dcomplaints_last_atus-complaint-reports | consumers reported unwanted calls from the number |
“Blocked by the default SMS policy” marks the default block_signals: a number carrying one is refused whatever the score. Every other signal only counts toward the default ceiling, which blocks a score above 60.
IP and address signals
These weights do not have pages of their own yet. Each guide lists them with the arithmetic:
- The IP risk score · 11 weights
- The address risk score · 17 weights