Email Verification API Reliability Guide
Mailthentic
email-verification By Mailthentic Editorial Team

Email Verification API Reliability: Timeouts, Retries, Rate Limits and Unknown Results

Operate asynchronous email verification safely with error classification, bounded retries, idempotency, caching, metrics, circuit breakers, and honest unknown states.

email verification API retries rate limits timeouts production reliability
Production email verification API workflow showing requests, timeouts, retries, rate limits, logging, and stable results

A reliable email verification integration treats submission, processing, and business decision as separate states. It sets timeouts, classifies errors before retrying, prevents duplicate jobs, keeps unknown results visible, and degrades according to an explicit product policy. The goal is not to force every address into valid or invalid. The goal is to preserve correct system behavior when networks and receiving mail servers are uncertain.

Mailthentic's single and bulk verification endpoints are asynchronous. A successful submission means the job was accepted, not that verification has finished. Production clients must store the job identity and poll the returned status and results URLs.

Use the verified Mailthentic contract

Send POST /api/verify/single with JSON containing one email. Authenticate server-side with Authorization: Bearer mt_..., or the supported X-API-Key header. An accepted single request deducts one credit and returns HTTP 202 with job_id, status_url, and results_url.

Use GET /api/jobs/{job_uuid}/status to observe progress and GET /api/jobs/{job_uuid}/results for paginated results. Bulk submission uses POST /api/verify/bulk with a CSV or XLSX multipart file. Use returned URLs where supplied so routing details remain centralized.

API-key callers require paid status and the correct scope. GET /api/me can test the credential without creating a verification or spending a credit.

Set separate timeout budgets

A connection timeout limits how long the client waits to establish a connection. A response timeout limits the HTTP exchange. A job deadline limits how long your product will wait for the asynchronous result before choosing a fallback. These values solve different problems.

Keep the initial HTTP timeout short enough to protect your application workers but long enough for normal request acceptance in your environment. Do not use the browser's patience as the verification job deadline. Continue polling from a background worker if the user interaction ends.

A timeout is an unknown submission outcome until proven otherwise. The server may have accepted the job even if the client did not receive the 202 response. Blindly repeating the POST can spend another credit and create duplicate work.

Classify HTTP responses before retrying

ConditionRetry?Production action
400 malformed requestNoFix validation or serialization and preserve the returned message
401 authentication failureNo automatic retryCheck secret loading or rotation and alert the owner
402 credit or paid-access errorNo until account state changesRoute to billing or operations without blaming the address
403 missing scope or permissionNo automatic retryCorrect key scope or access policy
413 request or job too largeNo unchanged retrySplit according to current tier and job rules
429 rate limitedYes, laterHonor returned guidance, back off with jitter, and reduce concurrency
Transient 5xxUsually bounded retryBack off, monitor, and open the circuit when sustained
Connection or response timeoutReconcile firstCheck known job state before creating another submission

The public API contract does not promise a fixed requests-per-second number. Treat 429 as the runtime authority. Do not hardcode an invented throughput claim into client behavior or documentation.

Handle 400 responses as engineering feedback

A 400 response indicates that the request did not meet the endpoint contract. Validate that the content type is JSON for single verification, the email field is present, and the payload shape is correct. For bulk, use multipart upload with a supported CSV or XLSX file.

Capture the status code, safe error code or message, endpoint, deployment version, and internal correlation ID. Do not retry the same malformed body. Alert on a sudden increase because it usually points to a deployment or schema change.

Separate authentication, subscription, and credit failures

A 401 points to a missing or invalid credential. A 403 can mean the key lacks the required scope. A 402 can indicate paid-access or credit state. These are operational account conditions, not properties of the submitted address.

Never expose the API key in client-side JavaScript, logs, analytics, screenshots, or error messages. Load it from the server's secret store. Test key rotation by supporting an overlap period or a controlled deployment, then revoke the old key.

Use exponential backoff with jitter

For an eligible transient failure, increase the delay after each attempt and add randomness so many workers do not retry together. Cap the delay and total attempts. Respect explicit server retry guidance when present.

A policy can be expressed as: next delay equals the smaller of a configured cap and a base delay multiplied by two to the attempt count, then adjusted by random jitter. The exact values belong in runtime configuration and load testing, not in article promises.

Retry reads more freely than submissions because GET requests should not create a new job. For POST reconciliation, first search your local state for an accepted job. If the submission outcome is unknown and the API has no client-supplied idempotency contract, prevent duplicate creation through your own state machine and controlled manual resolution.

Implement idempotency around business events

Mailthentic's documented single request contains an email field and does not publish a client idempotency-key field. Create an internal key from the stable business event, such as signup record ID plus workflow version. Store one submission record with states like pending-submit, accepted, polling, completed, failed-retryable, and failed-final.

Acquire a database lock or unique constraint before submitting. If the browser repeats a request, return the existing local state. Store the returned job_id before releasing the lock. This does not change the external API; it makes your caller idempotent.

Cache results with a clear freshness policy

Caching can avoid repeat checks when the same normalized address appears in a short period. Cache the result time, native status, reason, relevant flags, and verification mode. Key the cache by a protected normalized identifier rather than exposing raw addresses broadly.

Do not cache forever. Addresses and domains change. Set freshness by use case, source, and consequence, and bypass or refresh after a known bounce, address edit, domain change, or long inactivity. Never let a cached valid result override a later opt-out or suppression.

Treat unknown as a valid system state

Unknown can reflect temporary DNS or SMTP failures, greylisting, protected provider behavior, connection problems, or insufficient evidence. It should not become valid merely to keep the signup moving, and it should not become invalid merely to simplify a database column.

Store the reason and evidence. Route retryable causes to a bounded later check. Route persistently ambiguous, high-value cases to review. Let the product apply an explicit pending, restricted, fail-open, or fail-closed decision. The signup decision guide describes those user-facing choices.

Keep temporary SMTP evidence separate

A receiving server can defer recipient checks through greylisting, throttling, capacity controls, or policy. A temporary response is not proof that the mailbox is invalid. Repeated rapid probing can worsen the condition.

Preserve smtp_response_code, smtp_connectable, mailbox_confirmed, SMTP availability fields, and fallback_reason when returned. Use the overall status and reason rather than building a universal rule from one code.

Log for diagnosis without leaking contact data

Use a structured log with internal correlation ID, local workflow state, endpoint name, HTTP status, attempt number, elapsed time, provider job ID after acceptance, safe error classification, and deployment version. Redact authorization headers and avoid full email addresses in shared logs.

At the result layer, record the native status and reason in the protected application database. Do not copy full SMTP transcripts or confidence breakdowns into high-volume general logs unless the access and retention need is approved.

Measure the complete state machine

  • Submission attempts, accepted jobs, and acceptance latency.
  • Poll attempts, job completion time, and jobs beyond deadline.
  • HTTP errors grouped by 400, 401, 402, 403, 413, 429, and 5xx.
  • Connection and response timeouts by network path.
  • Retry attempts, retry success, exhausted retries, and circuit state.
  • Result distribution by source and verification mode.
  • Unknown and temporary reasons without high-cardinality raw text labels.
  • Duplicate submissions prevented by the local idempotency layer.
  • Credits consumed compared with accepted business events.

Build service-level objectives around your integration, such as the proportion of accepted jobs reaching a terminal state within your tested deadline. Do not convert internal observations into public speed guarantees.

Alert on actionable conditions

Alert when authentication or scope failures appear, credit errors threaten the workflow, 429 or 5xx rates remain elevated, pending jobs age beyond the operating threshold, the circuit opens, or result distribution changes sharply for one source. Use a lower-severity notification for a small transient retry spike.

Attach a runbook: verify service health, check the account and key using the safe endpoint, inspect recent deployment changes, pause new submissions if needed, drain accepted jobs, and invoke the product fallback. Alerts without an owner and response path create noise.

Use a circuit breaker to protect both systems

A circuit breaker stops new external calls after a sustained failure threshold. While open, the application follows its approved fallback and periodically allows a limited probe. After successful probes, it closes gradually.

Do not open the circuit because addresses return invalid or unknown. Those are domain results, not service failures. Trigger on transport, server, authentication, or other operational signals selected by the owner. Keep already accepted jobs polling when safe, even if new submissions pause.

Choose fail-open or fail-closed by action

Fail-open may create a pending account or queue a contact without granting sensitive capability. Fail-closed may be appropriate for a narrowly defined high-risk event, but it couples that event's availability to verification. Decide per action and document the consequence.

Never show “invalid email” when the real cause is an API outage, missing credit, timeout, or open circuit. Tell the user the check could not complete, preserve their input, and offer the approved next step.

Safe production pseudocode

event = load_or_create_event(source_id, workflow_version)
if event.job_id:
    return poll_known_job(event.job_id)

if circuit.is_open():
    return apply_fallback(event, reason="verification_unavailable")

with lock(event.id):
    if event.job_id:
        return poll_known_job(event.job_id)
    response = submit_single(email, timeout=CONFIGURED_TIMEOUT)
    if response.status == 202:
        save_job(event, response.job_id, response.status_url, response.results_url)
        enqueue_poll(event.id)
    elif is_retryable(response):
        schedule_with_backoff_and_jitter(event)
    else:
        save_final_operational_error(event, response.safe_error)

The pseudocode is deliberately framework-neutral. Add transactions, secret management, request validation, safe serialization, observability, and tests that fit your stack. The critical behavior is reconciliation before resubmission and separation between an operational error and an address result.

Test failures before production traffic

Test malformed payloads, invalid and under-scoped keys, paid-access or credit errors, oversized bulk requests, 429, transient 5xx, connection reset, response timeout before and after acceptance, slow polling, terminal failed jobs, unknown results, duplicate browser submissions, worker restart, and circuit recovery. Confirm that no test leaks keys or personal data.

Start with the API playground for contract exploration and the API tutorial for introductory integration context. Production reliability begins when the happy path stops being the only tested path.

Build against asynchronous reality

Review the Mailthentic API contract, store accepted job identities, and test retry, timeout, and fallback behavior before routing production decisions.

Share:
Updated

Ready to verify your email list?

Start free with 50 verification credits. No credit card required.