Build email verification into anything.
ZeMail is an API-first product. Verify a single address in real time or push millions in bulk, in any language, over plain REST. This page has everything: auth, endpoints, SDKs, webhooks, and a live sandbox you can hit right now.
Try it live — no key needed
This calls the public sandbox endpoint GET /v1/try with deterministic fixtures (no billing, no real SMTP). Try local-parts like valid.jane@…, invalid.bob@…, catchall.x@…, or a real typo like someone@gmial.com.
https://verify.datomatic.ai/v1.Quickstart
Three steps: grab a key, verify an address, read the bucket.
- Create a key in the dashboard —
dvk_live_…(real) ordvk_test_…(sandbox). - Call
/v1/verifywith a Bearer token. - Send to deliverable, decide on risky via score, drop undeliverable.
Authentication
Every request needs a Bearer API key in the Authorization header. Keys are server-side only — never ship a live key in client-side code.
Authorization: Bearer dvk_live_xxxxxxxxxxxxxxxx| Prefix | Mode | Behavior |
|---|---|---|
dvk_live_ | Live | Real DNS/SMTP verification. Consumes 1 credit per determinate result; unknown is free. |
dvk_test_ | Sandbox | Deterministic fixtures, no network, never charged. Perfect for CI + load tests. |
Sandbox & test keys
A dvk_test_ key returns deterministic results driven by the local-part, so your integration tests never depend on real mailboxes or spend credits — and bulk batches run with no SMTP so you can load-test at any scale.
| Local-part contains | Returns |
|---|---|
invalid / bounce | undeliverable · mailbox_not_found |
catchall | risky · catch-all |
unknown | unknown (free) |
| anything else | deliverable · valid |
Verify one email
Real-time, sub-second on popular domains. Runs on a high-priority lane so single verifies never wait behind bulk lists. Billed 1 credit per determinate result (valid / invalid / catch-all / risky); unknown is always free.
Output & buckets
Every verification returns a rich object. The one field to build on is bucket — the action-ready roll-up of the granular status.
{
"email": "john@company.com",
"status": "valid", // valid|invalid|catch-all|unknown|spamtrap|abuse|do_not_mail
"sub_status": null,
"score": 96, // 0-100 confidence (null when unknown)
"bucket": "deliverable", // deliverable|risky|undeliverable|unknown
"domain": "company.com",
"free_email": false, "role_based": false, "disposable": false,
"catch_all": false, "mx_found": true,
"mx_record": "aspmx.l.google.com", "smtp_provider": "google",
"domain_age_days": 6840, "did_you_mean": null,
"enhanced": false, "processing_ms": 740
}| Bucket | Meaning | Recommended action |
|---|---|---|
| deliverable | Mailbox confirmed | Send |
| risky | Catch-all / role / low corroboration | Decide via score (e.g. ≥ 85) |
| undeliverable | Positive proof it bounces | Discard |
| unknown | Couldn't determine — never charged | Retry later |
Bulk batches
Send a JSON array or upload a CSV/XLSX. You get a batch_id immediately (202); prefer a webhook_url over polling. Send an Idempotency-Key so retries never double-charge.
Find an email
Give a person's name and their company domain — we generate the likely address formats, rank them by the domain's known pattern (the same intelligence behind catch-all resolution), and SMTP-verify to return the deliverable one. Billed 1 credit only when found; not_found / unknown is free. On a catch-all domain you get a confidence-scored "catch-all" best guess instead of a false "valid". Same price as verification, billed independently — a verify is 1 credit, a find is 1 credit, and doing both is 2.
curl -X POST "https://verify.datomatic.ai/v1/find" \
-H "Authorization: Bearer dvk_live_xxx" \
-H "Content-Type: application/json" \
-d '{"first":"jane","last":"doe","domain":"acme.com"}'
# Multiple (up to 25) — bills 1 credit per FOUND address:
curl -X POST "https://verify.datomatic.ai/v1/find/batch" \
-H "Authorization: Bearer dvk_live_xxx" \
-H "Content-Type: application/json" \
-d '{"people":[{"first":"jane","last":"doe","domain":"acme.com"},
{"full_name":"John Smith","domain":"stripe.com"}]}'{
"found": true,
"email": "jane.doe@acme.com",
"status": "valid", // valid | catch-all | not_found | unknown
"confidence": 0.92, // 0..1
"pattern": "{word}.{word}", // matched local-part shape
"domain": "acme.com",
"first": "jane", "last": "doe",
"mx_found": true, "is_catch_all": false,
"candidates_tried": 1,
"alternates": ["jane.doe@acme.com", "jdoe@acme.com", "janedoe@acme.com"]
}valid is SMTP-confirmed. When the domain accepts all recipients, we never fake a confirmation — you get status:"catch-all" with a confidence you can threshold on.Domain health
A DNS-only inspection of a domain's sending setup — MX, SPF, DKIM, DMARC, and Spamhaus DBL blocklist status — with a 0–100 score, an A–F grade, and prioritized fixes. Free (no credits, no SMTP), so you can run it as often as you like — great as a lead magnet or a pre-send check.
{
"domain": "acme.com",
"score": 82, "grade": "B",
"mx": { "found": true, "records": ["aspmx.l.google.com"] },
"spf": { "found": true, "record": "v=spf1 include:_spf.google.com ~all", "policy": "~all" },
"dkim": { "found": true, "selectors": ["google"] },
"dmarc": { "found": true, "policy": "none", "record": "v=DMARC1; p=none; rua=..." },
"blacklisted": false,
"issues": ["DMARC is 'p=none' (monitor only) — move to 'quarantine' then 'reject' once clean."]
}Webhooks
Set webhook_url on a batch and we POST a signed batch.completed event when it finishes. Verify the HMAC-SHA256 signature over {timestamp}.{rawBody} and reject stale timestamps.
| Header | Value |
|---|---|
X-ZeMail-Signature | hex HMAC-SHA256 |
X-ZeMail-Timestamp | unix seconds |
X-ZeMail-Event | batch.completed |
Errors, limits & idempotency
Errors use a consistent envelope: { "error": { type, code, message, doc_url } }. Every official SDK auto-retries 429 and 5xx honoring Retry-After.
| Status | Meaning |
|---|---|
200 / 202 | OK / batch queued |
400 / 401 | Validation error / bad key |
402 | Out of credits — top up to continue. (unknown results are never charged.) |
429 | Rate limited — honor Retry-After |
5xx | Retry with backoff |
- Idempotency: send
Idempotency-Key: <uuid>on batch creation — retries never double-charge. - Rate limits:
X-RateLimit-Limit/Remaining/Resetheaders; higher tiers get a wider lane. - Billing:
unknownis never charged; enhanced credits never expire.
SDKs — every major language
Official, dependency-light clients with the same surface everywhere: verify, batch create/wait/download, account, and a webhook-signature verifier with automatic retry.
Any other language? Generate a client from the OpenAPI spec or call REST directly.