Result Statuses
Every validation result tells you what it means for sending in four fields: status, sub_status, explanation and recommended_action. This page lists every value they can have.
The fields
The four fields are the last fields of every result: from the validation endpoint, from the getInfo tool of the MCP server, in the JSON results of bulk jobs and with sandbox keys.
{
...
"status": "invalid",
"sub_status": "mailbox_not_found",
"explanation": "The mail server said that this mailbox does not exist.",
"recommended_action": "suppress"
}
- Name
status- Type
- string
- Description
What the result means for sending:
valid,invalid,catch_all,risky,do_not_mailorunknown.
- Name
sub_status- Type
- string or null
- Description
Why the result has its status.
nullfor a plainvalidresult.
- Name
explanation- Type
- string
- Description
One fixed English sentence per
sub_statusthat you can show to people. It never quotes the mail server's reply.
- Name
recommended_action- Type
- string
- Description
What to do with the address:
send,send_with_caution,suppressorretry_later.
Build your logic on status, sub_status and recommended_action. The explanation is meant for people; do not compare or parse it.
Statuses
| status | Meaning | recommended_action |
|---|---|---|
valid | The mailbox exists | send; send_with_caution for a role address or a possible typo |
invalid | Mail to the address bounces: the format is not valid, the domain does not accept mail, or the mailbox does not exist | suppress |
catch_all | The domain accepts mail for any address, so whether this mailbox exists cannot be confirmed | send_with_caution |
risky | The mailbox may exist, but sending to it is a risk. Live validation returns it for a full mailbox | retry_later for a full mailbox; send_with_caution for the risky sandbox addresses |
do_not_mail | The address belongs to a disposable (temporary) email provider | suppress |
unknown | We could not get a definite answer from the mail server | retry_later; send_with_caution when the mail server's anti-spam system blocked the check permanently |
Reserved statuses
spamtrap and abuse are reserved for future risk data (spam traps and addresses known to complain). They are not returned yet. If your code switches on status, give them a branch now, for example the same as do_not_mail.
Sub-statuses
| sub_status | status | explanation | recommended_action |
|---|---|---|---|
null | valid | The mail server confirmed that this mailbox exists. | send |
relay_address | valid | The address is a forwarding alias of a privacy relay service (such as Apple Hide My Email); mail reaches the owner's own inbox. | send |
alias | valid | The mailbox exists; the +tag in the address is delivered to the same mailbox as the address without it. | send |
role_based | valid | The mailbox exists, but it is a role address (such as info@ or support@), usually read by a team rather than one person. | send_with_caution |
possible_typo | valid | The mailbox exists, but the address looks like a typo; see did_you_mean for the likely intended address. | send_with_caution |
failed_syntax_check | invalid | The address is not a valid email address. | suppress |
does_not_accept_mail | invalid | The domain declares that it does not accept email (null MX record). | suppress |
no_dns_entries | invalid | The domain does not exist or has no mail server, so mail to it cannot be delivered. | suppress |
unroutable_ip | invalid | The domain's mail server has only private or reserved IP addresses, which cannot be reached from the internet. | suppress |
mailbox_not_found | invalid | The mail server said that this mailbox does not exist. | suppress |
mailbox_disabled | invalid | The mail server said that this mailbox is disabled or inactive. | suppress |
accept_all | catch_all | The domain accepts mail for any address (catch-all), so whether this mailbox exists cannot be confirmed. | send_with_caution |
mailbox_full | risky | The mailbox exists but is full; mail bounces until its owner frees up space. | retry_later |
null | risky | The mailbox may exist, but sending to it is a risk. (Sandbox keys only.) | send_with_caution |
disposable | do_not_mail | The address belongs to a disposable (temporary) email provider. | suppress |
antispam_system | unknown | The mail server's anti-spam system refused the check, so the mailbox could not be verified. | retry_later when the block was temporary, send_with_caution when it was permanent |
greylisted | unknown | The mail server asked to try again later (greylisting), so the mailbox could not be verified yet. | retry_later |
mail_server_temporary_error | unknown | The mail server reported a temporary problem, so the mailbox could not be verified. | retry_later |
timeout_exceeded | unknown | The mail server did not answer in time, so the mailbox could not be verified. | retry_later |
failed_smtp_connection | unknown | The domain's mail server could not be reached, so the mailbox could not be verified. | retry_later |
forcible_disconnect | unknown | The mail server closed the connection during the check, so the mailbox could not be verified. | retry_later |
dns_lookup_failed | unknown | The domain's DNS servers failed to answer the mail server lookup, so the mailbox could not be verified. | retry_later |
exception_occurred | unknown | The check failed on our side, so the mailbox could not be verified. | retry_later |
An anti-spam block that is permanent says something about our connection to the mail server, not about the mailbox, which is why it is send_with_caution rather than retry_later.
New sub_status values may be added. Handle a value you do not know by its status and recommended_action.
When several apply
A result has one status and one sub-status. When more than one applies, the first match in this order wins:
- The address has no valid format, or the mail server or DNS showed that mail to it bounces:
invalid. - The address belongs to a disposable email provider:
do_not_mail. This applies even when the mail server gave no answer, but not to privacy relay services (see 5), which are on some disposable lists. - The mail server gave no definite answer:
unknown. - The mailbox is full:
risky/mailbox_full. - The address belongs to a privacy relay service:
valid/relay_address, even whendisposableistrue. - The domain is a catch-all domain:
catch_all/accept_all. - The address is a role address:
valid/role_based. - There is a
did_you_meansuggestion:valid/possible_typo. - The address has a +tag:
valid/alias.
For example, info@ on a catch-all domain is catch_all, not role_based; the role field is still true.
Status and state / reason
status and sub_status come from the same check as state and reason, which are still returned. They give a finer breakdown: reason low_deliverability, for example, can mean a catch-all domain, a disposable address or a full mailbox, and status tells them apart. The usual combinations:
| state | reason | status (sub_status) |
|---|---|---|
deliverable | valid_mailbox | valid (null, relay_address, alias or possible_typo) |
deliverable | low_quality | valid (role_based) |
deliverable | low_deliverability | catch_all (accept_all), do_not_mail (disposable) or risky (mailbox_full) |
undeliverable | invalid_format | invalid (failed_syntax_check) |
undeliverable | invalid_mx | invalid (no_dns_entries, does_not_accept_mail or unroutable_ip) |
undeliverable | invalid_mailbox | invalid (mailbox_not_found or mailbox_disabled) |
unknown | unavailable_smtp | unknown (antispam_system, greylisted or mail_server_temporary_error) |
unknown | timeout | unknown (timeout_exceeded, or exception_occurred when our validation service could not be reached) |
unknown | no_connect | unknown (failed_smtp_connection or forcible_disconnect) |
unknown | unexpected_error | unknown (dns_lookup_failed or exception_occurred) |
A disposable address is do_not_mail whatever its state, unless it is undeliverable or belongs to a privacy relay service. What a check costs depends on state and reason, not on status; see Rate Limit & Quotas.
Catch-all on every plan
status is catch_all for an address on a catch-all domain on every plan, whether or not you set the catch_all parameter. The catch_all field itself stays null unless you send catch_all=1 on a plan that includes catch-all detection.
Using recommended_action
| recommended_action | What to do |
|---|---|
send | Send to the address. |
send_with_caution | The address exists or may exist, but carries a risk. Decide by sub_status whether it fits your use: for example, ask a user who signs up with a possible_typo address to confirm it, or send to catch_all addresses in a separate, smaller batch. |
suppress | Do not send to the address. |
retry_later | Check the address again later. The mail server may answer next time, and a full mailbox may be emptied. |
Unknown results are free within a fair-use allowance, but checking the same address again within an hour after an unknown result counts against your quota. See Unknown results.
Bulk jobs
The JSON results of bulk jobs have all four fields. The CSV results have emailvalidation_status, emailvalidation_sub_status and emailvalidation_recommended_action as their last three columns; the explanation is in the JSON results only. The results of jobs that finished before these fields were added were saved then: they have only the earlier 15 fields and columns.
Testing
Sandbox keys return these fields too. Their test addresses cover each status, including a full mailbox, a greylisted check and an anti-spam block.