OKKI Go research note

Email Verification API: Handle Unknown Results as First-Class States

Build an email verification API caller with request ownership, separate timeout and pending states, bounded polling, retry accounting, and explicit job closure.

Build an email verification API caller around an immutable attempt, operation progress, and a received verdict. Treat Hunter 202 and Emailable 249 as documented continuation paths, distinguish a local timeout from a provider’s unknown result, and close follow-up when its budget expires. Persist the result against the original request before updating the current address.

Define the Decision Your Application Needs from Verification

An email verification API evaluates an address you already have, but the caller also has a job to finish. Can you tell whether a request is still running, whether a verdict arrived, and which address that verdict belongs to? Design those distinctions before connecting the endpoint.

Requested checks and immutable attempt inputs

Hunter exposes separate format, domain and SMTP checks. Keep their meaning available, but start your caller record with the inputs to this attempt: the submitted address, provider and endpoint, requested checks, and a local attempt identifier. These proposed application fields describe what you asked, so the result cannot silently inherit assumptions from a different request.

Catch-all means the server accepts addresses without establishing that each mailbox exists; Hunter warns of SMTP false positives in that condition. Your adapter therefore needs to preserve whether the observation was made. The implementation question is narrower than a sending-policy decision: did this response answer the checks you requested?

Operation progress versus completed verdicts

ZeroBounce documents unknown when a server is slow or greylisting intervenes. That is still a received provider result. If your network client stopped waiting without receiving a response, you have a different event: completion is unconfirmed locally. Do not assign the provider’s unknown label to an observation your client never received.

Use three local concepts: the attempt identity, operation progress, and any received mailbox verdict. You can close a completed operation with an unknown verdict; you can also have an open operation with no verdict yet. This is the proposed caller model used below, not a shared vendor response schema.

Map Vendor Statuses Without Erasing Uncertainty

Did you receive a verdict or an instruction to continue? Your adapter must recognize that difference before parsing mailbox fields. You cannot send both response shapes through the finished-result parser. Route continuation responses to the scheduler, where you can check whether another call is still permitted.

Provider timeout versus client timeout

For a received Hunter verdict, read status rather than its deprecated result field. For Emailable, the finished result uses state with reason. Put those fields in your verdict record. If you receive a pending response instead, do not reject it for lacking a deliverability field.

ZeroBounce’s timeout parameter, checked September 2026, accepts 3–60 seconds and defaults to 30. Its documented limit can produce unknown / greylisted. Store that as a received result for this attempt. A local transport timeout should instead record that no response was obtained before your deadline. You cannot infer that provider work stopped, or that another call is free.

Emailable’s accept_all request option defaults to false; its sample response contains accept_all: null. Preserve the option you sent as well as the returned value. If you later enable the check, record the changed options as a new attempt configuration. Otherwise two responses for the same address can look comparable even though you asked different questions.

Request options and missing observations

Emailable documents a separate message response when verification exceeds its timeout. Your parser should keep that continuation response outside the finished-verdict path. Preserve the HTTP code and body together, and populate verdict fields only from a response shape the endpoint documents as a verification result. These are adapter recommendations; they do not add vendor fields.

What should your parser require? Define required fields for each documented response shape. Keep nullable observations intact and the original body available. If parsing fails, record that local failure without manufacturing a verdict. Hunter’s move from result to status illustrates why this mapping needs an explicit version.

Can you reconstruct the request that produced the stored verdict? Retain your endpoint mapping version, submitted options, local request time and response receipt time. These are proposed local metadata, not provider timestamps. They let you investigate whether an apparent result change came from different checks, a new response, or a parser change.

Design Retry and Queue Behavior for Ambiguous Responses

With response shapes separated, decide what the next network call means. Polling asks for completion of work in progress; retrying attempts an operation again after failure. Hunter and Emailable document follow-up differently. Your scheduler must preserve that distinction instead of repeating every call that lacks a finished verdict.

A temporary failure is not a confirmed invalid address

Hunter’s Email Verifier reference, checked September 2026, says a request runs for 20 seconds before returning HTTP 202 if a result is not ready. It permits polling the same endpoint and counts those requests once until the response arrives. Record the operation as pending, retain the original address, and schedule that documented continuation. Do not close the job as unknown merely because a 202 arrived.

Hunter separately documents HTTP 222 for an unexpected remote SMTP response and recommends retrying later. That is a failure path, not the documented 202 polling path. The cited instruction gives no retry interval. Choose a local delay and attempt cap under your service constraints, mark them as application policy, and keep the failure available when the retry runs.

Give each local attempt immutable inputs and keep a separate reference to the currently relevant attempt. As a design rule, accept a late response into the current contact record only if its submitted address and attempt reference still match. If an address changed while you waited, save the old response under the old attempt. You can close that work without overwriting the newer request.

Latency, credits, and asynchronous processing

Emailable documents HTTP 249 when single-email verification exceeds its timeout. Its current range is 2–10 seconds, defaulting to 5. Repeat requests are allowed for up to 5 minutes before further requests count against usage. Treat the 249 as the endpoint’s continuation instruction. The five-minute window concerns accounting; it is not an instruction to delay your first follow-up for five minutes.

Declare three local limits before scheduling: how long the interface waits, how long the background job may remain open, and how many follow-up calls you permit. Also decide how you account for provider usage. These are design choices, not universal API constants. A form can stop waiting while a worker continues, but the worker still needs a deadline and a budget it checks before each call.

Persist the next permitted attempt time, calls already made, and terminal reason in your proposed job record. Before you call again, check both the remaining budget and whether this is still the current attempt. A received completed verdict closes the operation, even when the verdict is unknown. Budget exhaustion closes it locally as unresolved; it must not manufacture a mailbox verdict.

Can a restarted worker resume without forgetting earlier calls? Save the follow-up decision before releasing the job, and use a local ownership rule so two workers do not intentionally schedule the same continuation. These are recommended safeguards, not claims that either provider offers idempotency. Hunter’s pending-request accounting and Emailable’s repeat-request window do not establish universal free retries after a lost response.

Choose an API by the Decisions Its Responses Support

The caller’s deliverable is a durable verification attempt with a defined ending. ZeroBounce supplies a useful counterexample to “timeout means failed address”: its validation limit can return unknown. Once that response arrives, you have a completed observation to store. A local timeout with no response leaves completion unconfirmed. Those events require different records before any downstream policy acts.

This is why an email verification API should be evaluated by timeout, unknown-state, catch-all, and retry behavior rather than advertised accuracy; production safety is decided at ambiguous responses. The endpoint contract must let your caller establish result ownership and choose whether work continues, starts again, or ends. An accuracy figure does not describe those transitions.

Persist, continue, retry, or close the verification job

For a caller operating alongside OKKI Go, keep this local job contract independent of any assumed native integration. Persist the attempt identifier and immutable inputs, operation state, last response, next-call decision, remaining budget, and terminal reason. Then implement the following proposed transitions against the documented endpoint behavior:

  • Continue the pending operation after Hunter 202 or Emailable 249 using that endpoint’s documented follow-up; keep the original attempt inputs.
  • Schedule a bounded retry after Hunter 222 only while local time and call budgets permit; retain the failure that prompted it.
  • Close as completed when a documented verdict arrives, including unknown; attach it to the matching attempt before updating the current record.
  • Close locally as unresolved when the budget expires without completion; retain any later response under its original attempt rather than reopening current work automatically.

Test those transitions with controlled response fixtures before deployment. A pending response must leave the verdict empty; a completed unknown must close the operation; a changed address must prevent a late result from overwriting current work. Repeat a pending response until your budget expires and restart a worker between calls. These are proposed acceptance tests, not executed tests or measured vendor outcomes.

Choose an API only after you can write down how its documented responses enter and leave this job model. Resolve unclear continuation and billing semantics before automating them. You deliver a result with known ownership, or an explicitly terminated unresolved attempt. The separate sending policy can consume that output without having to infer what the network call actually did.

Frequently asked questions

Does unknown mean that an email address is invalid?

No. For the caller, distinguish a received unknown verdict from having no response. A completed provider result can close the operation while leaving the mailbox uncertain. A local transport timeout leaves completion unconfirmed and requires a separate follow-up decision.

Should an application retry a verification timeout?

First identify the event. Hunter 202 and Emailable 249 document continuation paths; Hunter 222 recommends retrying later. A local timeout does not prove which provider state occurred. Follow the endpoint contract and stop when your declared time or call budget is exhausted.

How should a late verification response be saved?

As an application design rule, save it under the immutable attempt and submitted address that produced it. Update the current contact only if that attempt is still relevant. A response for an earlier address should not overwrite the verdict for a newer address.