Result codes

The result field

Four results, and the interesting one is last. Valid, invalid, catch-all, unknown. The result field answers one question, whether this mailbox exists, and those are the only four answers SMTP can honestly give. On the wire the third is spelled catch_all, with an underscore, like every other value in this API.

Role, disposable and free provider are not results. They're booleans that sit beside result, because they describe the address and say nothing about the server's answer. A role address can be valid or invalid, and a disposable domain can be catch-all. Fold them into one field and you lose that. You'd also need a precedence rule nobody remembers.

Each result traces back to something the receiving server said. The smtp_code field carries that raw response, so you can audit how we read it rather than taking our word for the mapping.

Unknown is a first-class result here. It means the server would not give a straight answer: greylisting, throttling, or an outright block on probe traffic from cloud addresses. We report it, we explain it, and we do not charge for it.

Fields

FieldTypeWhat it carries
resultstringOne of valid, invalid, catch_all, unknown. Branch your pipeline on this.
reasonstringThe narrower cause, such as mailbox_not_found or greylisted. Every value is in the reasons table below.
smtp_codestring or nullThe literal server response. Null when the handshake never got as far as RCPT TO.
role, disposable, free_providerbooleanFlags about the address. Never values of result.
billedbooleanTrue on valid, invalid and catch_all. False on every unknown and every collapsed duplicate.

Reference

resultSMTP behavior behind itBilled
validRCPT TO answered 250 and the domain is not accept-all.Yes
invalidA definite no: no such domain, no mail server, or a 5xx for this recipient. (A row rejected on syntax alone is invalid too, and is the one invalid that is free.)Yes
catch_all250 for the real address and 250 for a random one at the same domain.Yes
unknown4xx, 252, 530, a timeout, or a block on the probe.No

Catch-all is a result, not a warning. It took a full handshake and a second probe, and it tells you something true about the domain, which is why it costs a credit and unknown does not.

Flags

FlagTrue whenHow we know
roleThe local part is a function and not a person: info@, sales@, support@.List lookup.
disposableThe domain belongs to a throwaway-mailbox provider.List lookup.
free_providerThe domain is a consumer mailbox provider such as gmail.com, yahoo.com or outlook.com.List lookup.

Flags are set on every response, unknown included. They come from the address itself and need no answer from the server, and they never change what you are billed.

Reasons

reasonresultWhat happened
accepted_emailvalidThe server accepted this recipient and rejected a random one.
invalid_syntaxinvalidThe string is not shaped like an email address. Seen in batch and file results only, and never billed: POST /verify rejects the same input as a 400 malformed_email.
domain_not_foundinvalidThe domain does not exist in DNS.
no_mail_serverinvalidNo MX record, and no A record to fall back on.
null_mxinvalidThe domain publishes a null MX, which says it accepts no mail at all (RFC 7505).
mailbox_not_foundinvalidThe server said no such user.
mailbox_disabledinvalidThe mailbox exists and has been closed or suspended.
mailbox_fullinvalidOver quota. This is the one invalid that can recover by itself, so check it again after 30 days.
accept_all_domaincatch_allThe server accepted a random address too.
greylistedunknownA 4xx asking us to come back later, and the retry did not settle it.
throttledunknownThe host rate-limited our probes.
probe_blockedunknownThe host refuses to discuss recipients with us, often a 530.
timeoutunknownNo reply inside your timeout budget.
temporary_failureunknownAnother 4xx that says nothing about the mailbox.
cannot_verifyunknownA 252: the server will accept the mail and won't confirm the address.

This list is closed today and can grow without a version bump. Branch on result, and treat a reason you don't recognize as extra detail.

What your code should do with unknown

The answer depends on who is waiting. At a signup form, accept the address and queue a recheck for later that night. In a bulk clean, put unknowns in a retry pile and resubmit them the next day. They weren't billed, so a second try costs nothing unless it gets a verdict. After two tries, move whatever is left into a segment you send separately and watch closely.

In a CRM, the trap is the data model. A boolean column called is_valid has two values, and unknown needs a third. Somebody will map it to false one day, and a few thousand real contacts will get suppressed without anyone deciding that they should be. Store the verdict as the string you received, with checked_at beside it.

Test this branch with the sandbox before you need it. In production it fires only when a mail host is having a bad day. That's a poor time to learn that your pipeline crashes on it.

Auditing a verdict you don't believe

Say a customer emailed you yesterday and today their address comes back invalid. Look at smtp_code first. A 550 means the server said no such user at the moment we asked. Compare the stored address with the one they wrote from, character by character, because a typo in your CRM is the usual cause.

For an unknown, the code tells you whether a retry is worth it. A 4xx is temporary, so try again tomorrow. With a 252 or a 530, you're looking at the server's policy, and asking again won't change its mind.

When a valid address bounces, check the age of the verdict in checked_at before you blame the check. People change jobs, and a verdict from four months ago describes a mailbox as it was back then.

None of this can confirm that a catch-all address is real. The raw code for those is a 250, same as a good mailbox, and that's exactly why the label exists.

Questions developers ask

Should I mail catch-all addresses?

Send to them separately from your valid segment and watch the bounce rate on that send alone. Then you are deciding on your own data instead of a vendor's guess.

Why is unknown not billed?

Because you would be paying for a non-answer. Charging for it also gives the vendor a reason to keep the unknown pile large, which is the wrong incentive to build into a price list.

Can a role address be worth keeping?

Often, for support and billing contact. It is flagged because open rates on shared mailboxes are poor and some ESPs treat them as a list-quality signal. The flag sits beside the result, so you still know whether the mailbox exists.

Is a catch-all result billed?

Yes, one credit. We ran the full handshake and a second probe, and the answer tells you something true about the domain. Unknown is the one result that is free, because there we found nothing out.

Do you remove spam traps?

No, and treat anyone who promises it carefully. A pristine trap looks exactly like a real mailbox over SMTP. We may flag a likely recycled trap by heuristic, labeled as a guess.

Try it against a sandbox key

Scripted verdicts, no SMTP connections, no credits. Live keys come with 100 free checks a month and no card.