You can verify an email address without sending anything by doing exactly what a sending mail server does up to the moment it would transmit the message: parse the address, look up the domain's mail servers in DNS, open an SMTP session, ask whether the recipient exists, and disconnect. The server's reply to that question is the verification. No message is transmitted, nothing lands in an inbox or a spam folder, and the recipient never knows.
What happens in an SMTP handshake?
SMTP is a conversation. A sending server connects to one of the recipient domain's mail exchangers on port 25 and the two exchange a fixed sequence of commands before any content moves. The recipient check happens at the RCPT TO step, which is why a verifier can stop right after it.
| Step | Command | What the reply tells a verifier |
|---|---|---|
| 1 | connect | Whether the host answers on port 25 at all |
| 2 | EHLO |
Which extensions the server supports; nothing about the mailbox yet |
| 3 | MAIL FROM |
Whether the server accepts the sender at all |
| 4 | RCPT TO |
Whether the server accepts mail for this exact recipient: 250 yes, 550 no, 4xx come back later |
| 5 | QUIT |
The verifier leaves without ever sending DATA |
A real message only starts with DATA, the step a verifier never issues. Everything before it is a question, and questions do not generate bounces or deliveries.
Why not just send a test email?
Sending a test message tells you less than a handshake and costs more. A test to a dead address produces a bounce, and bounces are the metric mailbox providers use to judge your reputation. A test to a spam trap gets your domain listed. A test to a real person is an unsolicited message. And the answer arrives asynchronously, minutes or hours later, in the form of a bounce notification you then have to parse.
The handshake answers in a second or two, synchronously, and leaves no trace on the receiving side beyond a log line.
Which checks come before the handshake?
Most addresses are settled before any SMTP connection is opened, which is cheaper and often more decisive.
| Check | What it catches | Spaw result |
|---|---|---|
| RFC 5322 syntax | Missing @, spaces, malformed domains |
invalid_syntax |
| Provider username rules | Usernames Gmail, Outlook, Yahoo, iCloud, AOL or Proton would never issue | invalid_local_part |
| DNS: MX and address records | Domains with no mail server, a null MX, or MX targets that do not resolve | no_mx_records, null_mx, mx_unresolvable |
| Implicit MX | Domains with only an A record, which almost never accept mail | implicit_mx |
| Disposable list | Temporary inbox providers, including new burner domains routed through a listed operator's mail hosts | disposable |
| Role list | Shared inboxes such as info@ or billing@ |
role |
| Typo-squat map | gmail.con, hotmial.com and similar, with a suggested correction |
likely_typo |
Every one of those is a live DNS query or an open list lookup. The DNS part matters more than it looks: a domain whose MX records point at loopback or private addresses will never receive mail, and a domain publishing a null MX record has declared that it does not want any. Both are answered without a handshake, and Spaw answers them for free.
What can the handshake not tell you?
Four things, and an honest verifier reports each of them instead of guessing.
A catch-all server answers 250 to every recipient, so the reply proves nothing about the specific mailbox. Corporate domains behind security gateways and many Microsoft 365 tenants work this way. Spaw reports catch_all: true with a risky verdict and adds mailbox_confidence, a recomputable estimate built from the domain's other signals.
Greylisting answers the first connection from an unknown sender with a temporary failure and expects a retry minutes later. A verifier cannot wait, so the mailbox stays unverified.
Timeouts and refused connections happen when a server slows sessions down on purpose, or when a firewall sits in front of it.
Providers that hide the answer. Some large providers accept every RCPT TO and reject later, or throttle verification traffic aggressively. Their addresses come back unverified more often than others.
In all four cases Spaw returns smtp_checked: false, mailbox_exists: null and an smtp_reason naming the cause, and the verdict rests on the checks above. You can ask for a second attempt: pass callback_url and the address is re-checked after 5 and 20 minutes, with the settled verdict pushed to you at no cost.
How to do it with the Spaw API
One request, one credit for a deliverable or risky answer, nothing for an undeliverable one.
curl https://spaw.co/api/v1/email \
-H "Authorization: Bearer sk_live_…" \
-H "Content-Type: application/json" \
-d '{"email": "[email protected]"}'
{
"success": true,
"data": {
"email": "[email protected]",
"deliverable": "deliverable",
"reason": null,
"risk_score": 0,
"mx_found": true,
"mx_provider": "google",
"smtp_checked": true,
"mailbox_exists": true,
"catch_all": false,
"smtp_reason": null,
"// 16 more fields": "see the endpoint reference"
},
"meta": { "credits_used": 1, "credits_remaining": 9, "cache_hit": false }
}
The same lookup runs behind the free email checker, the dashboard, the batch endpoint for up to 50 addresses, and bulk jobs for up to 100,000. Six fixed addresses at spaw.test, such as [email protected], answer canonical verdicts at no cost for integration tests.
How to do it yourself
The handshake is simple enough to type by hand, which is the best way to understand it.
$ nc aspmx.l.google.com 25
220 mx.google.com ESMTP
EHLO verifier.example.com
250-mx.google.com at your service
MAIL FROM:<[email protected]>
250 2.1.0 OK
RCPT TO:<[email protected]>
550-5.1.1 The email account that you tried to reach does not exist.
QUIT
221 2.0.0 closing connection
Doing this at scale is where the difficulty starts. Most cloud providers block outbound port 25 by default. Receiving servers check the connecting IP's reverse DNS and reputation, and an IP that opens thousands of sessions without ever sending mail looks like an address harvester and gets throttled or blocked. Greylisting needs retry queues, catch-all detection needs per-domain memory, and every provider has its own quirks. That is the work a verification service does for you, and it is why Spaw runs the handshake through partner infrastructure with the guards described above rather than from the same machines that serve the API.
What to do next
- Try an address in the free email checker and read the
reasonandsmtp_reasonfields against the verdict reference. - Verify a list before a campaign with the batch or bulk endpoint; undeliverable answers are free.
- Report delivery outcomes back through the feedback endpoint so catch-all and unverified addresses at your domains get settled by real deliveries.
- Read what a catch-all address is before deciding how to treat risky verdicts.