---
title: "MX Lookup API: Domain Mail Routing and Provider Data | Emvero"
description: "Get MX records, routing, provider matches and published SPF and DMARC through one domain API request. Read field freshness, partial results and safe retries."
url: https://emvero.io/domain-intelligence-api/
language: en
updated: 2026-10-08
---

MX lookup API

# Look up MX records and domain mail data through one API.

Request MX records, mail routing and provider information for one domain. The JSON profile also includes SPF/DMARC, known domain signals and IP-to-ASN attribution. Add variant=extended for registry registration data.

The JSON response keeps each observation’s status, source and freshness. Domain Intelligence does not open an SMTP session, verify a mailbox or authenticate a message.

Start for free

View documentation

GET for one domain · Structured JSON · Required Idempotency-Key · Shared credits

## Request one domain from your backend

The endpoint is `GET /v1/domain/{domain}`. Send the domain in the path, an API credential in `Authorization: Bearer` and a required `Idempotency-Key`. Keep the credential on your server. The request has no body. The optional query parameter `variant` accepts `standard` (the default) or `extended`.

```
curl -sS https://api.emvero.tech/v1/domain/example.com \
  -H "Authorization: Bearer emv_your_credential" \
  -H "Idempotency-Key: 3f0c9a52-6d1e-4b8e-a7f4-2c51d0e9b6aa"
```

`example.com` and the values in the documentation are synthetic. Use a domain, not an email address, URL or IP address. Each request looks up one domain; a subdomain is checked as itself.

For registration data, add `?variant=extended` and use a new key for this separate operation:

```
curl -sS "https://api.emvero.tech/v1/domain/example.com?variant=extended" \
  -H "Authorization: Bearer emv_your_credential" \
  -H "Idempotency-Key: 8c1d2e7a-4b9f-4f0e-9a3c-61e5d2b7c904"
```

**View a complete JSON response · Extended**

Synthetic example. Standard returns registration: null and billing.variant: standard. The example below includes registration and costs 2 credits as a new complete Extended operation. 
```
{
  "schema_version": "1",
  "operation_id": "45eb36a9-b4e6-48ac-94a9-0ad145b6cf98",
  "domain": "example.com",
  "ascii_domain": "example.com",
  "status": "complete",
  "generated_at": "2026-10-02T10:00:00Z",
  "mail_routing": {
    "status": "routable",
    "method": "mx",
    "issues": [],
    "meta": {
      "status": "ok",
      "reason": null,
      "source": "dns",
      "source_version": null,
      "observed_at": "2026-10-02T10:00:00Z",
      "expires_at": "2026-10-02T10:05:00Z",
      "stale": false
    }
  },
  "mx": {
    "records": [
      {
        "host": "mx.example.com",
        "priority": 10,
        "provider_id": null
      }
    ],
    "provider_id": null,
    "provider_match": "unknown",
    "truncated": false,
    "meta": {
      "status": "ok",
      "reason": null,
      "source": "dns",
      "source_version": "catalog:17",
      "observed_at": "2026-10-02T10:00:00Z",
      "expires_at": "2026-10-02T10:05:00Z",
      "stale": false
    }
  },
  "email": {
    "classification": {
      "disposable": false,
      "public_provider": false,
      "meta": {
        "status": "ok",
        "reason": null,
        "source": "dataset",
        "source_version": "bundle:example-v1",
        "observed_at": null,
        "expires_at": null,
        "stale": false
      }
    },
    "catch_all": {
      "state": "unknown",
      "provider_id": null,
      "meta": {
        "status": "unknown",
        "reason": "not_observed",
        "source": null,
        "source_version": null,
        "observed_at": null,
        "expires_at": null,
        "stale": false
      }
    }
  },
  "email_authentication": {
    "spf": {
      "present": true,
      "syntax": "valid",
      "record": "v=spf1 -all",
      "all_qualifier": "fail",
      "includes": [],
      "redirect": null,
      "evaluation": "not_performed",
      "issues": [],
      "meta": {
        "status": "ok",
        "reason": null,
        "source": "dns",
        "source_version": "spf-syntax:1",
        "observed_at": "2026-10-02T10:00:00Z",
        "expires_at": "2026-10-02T10:05:00Z",
        "stale": false
      }
    },
    "dmarc": {
      "present": true,
      "syntax": "valid",
      "record": "v=DMARC1; p=reject",
      "policy_domain": "example.com",
      "inherited": false,
      "published_policy": "reject",
      "effective_policy": "reject",
      "testing": false,
      "adkim": "r",
      "aspf": "r",
      "evaluation": "not_performed",
      "issues": [],
      "meta": {
        "status": "ok",
        "reason": null,
        "source": "dns",
        "source_version": "dmarc-rfc9989:1",
        "observed_at": "2026-10-02T10:00:00Z",
        "expires_at": "2026-10-02T10:05:00Z",
        "stale": false
      }
    }
  },
  "network": {
    "mail": [
      {
        "host": "mx.example.com",
        "priority": 10,
        "addresses": [
          {
            "ip": "198.51.100.25",
            "asn": 64500
          },
          {
            "ip": "203.0.113.25",
            "asn": 64511
          },
          {
            "ip": "2001:db8::25",
            "asn": 64500
          }
        ]
      }
    ],
    "web": {
      "host": "example.com",
      "cname_chain": [],
      "addresses": [
        {
          "ip": "198.51.100.80",
          "asn": 64500
        },
        {
          "ip": "2001:db8::80",
          "asn": 64500
        }
      ],
      "truncated": false,
      "edge_provider": null,
      "meta": {
        "status": "ok",
        "reason": null,
        "source": "dns",
        "source_version": null,
        "observed_at": "2026-10-02T10:00:00Z",
        "expires_at": "2026-10-02T10:05:00Z",
        "stale": false
      }
    },
    "autonomous_systems": [
      {
        "asn": 64500,
        "handle": "EXAMPLE-ISP",
        "name": "Example Access",
        "country": "DE",
        "type": "isp"
      },
      {
        "asn": 64511,
        "handle": null,
        "name": null,
        "country": null,
        "type": "unknown"
      }
    ],
    "meta": {
      "status": "ok",
      "reason": null,
      "source": "dataset",
      "source_version": "example-routing-dataset",
      "observed_at": "2026-10-02T00:35:16Z",
      "expires_at": null,
      "stale": false
    }
  },
  "registration": {
    "registered_domain": "example.com",
    "registered_at": "2020-10-02T10:00:00Z",
    "age_days": 2191,
    "expires_at": "2027-10-02T10:00:00Z",
    "registrar": "Example Registrar",
    "statuses": [
      "client transfer prohibited"
    ],
    "meta": {
      "status": "ok",
      "reason": null,
      "source": "registry",
      "source_version": "rdap.example.com",
      "observed_at": "2026-10-02T10:00:00Z",
      "expires_at": "2026-11-01T10:00:00Z",
      "stale": false
    }
  },
  "billing": {
    "product": "domain-intelligence",
    "variant": "extended",
    "operation_credits": 2
  }
}
```

## Read routing, MX records and the provider match

`mail_routing.status` describes the domain’s route. `mx.records` lists receiving hosts and their priorities. A route does not establish that a named recipient will be accepted. The [MX glossary](https://emvero.io/glossary/mx-record/) explains the underlying DNS record.

`mx.provider_match` is `matched`, `mixed`, `unknown` or `not_applicable`. Matching identifies the visible incoming operator when the preferred hosts agree. That operator can be a filtering gateway rather than the mailbox host. `mx.truncated` indicates that the record list was shortened. See [how to find an email provider](https://emvero.io/blog/how-to-find-email-provider/) for the attribution limits.

`email.classification` contains known disposable and public-provider signals. A negative classification means no reference-list match, not proof of the opposite. `email.catch_all.state` reports the state already held for the domain; this lookup makes no new SMTP probe to establish it.

`email_authentication` contains supported SPF and DMARC publication data. Their `evaluation` is `not_performed`: the API does not test a message or sender, discover DKIM keys or recursively evaluate SPF includes. Sending reputation and domain ownership are outside the profile.

## Read network and registration fields

`network.mail` groups public IP addresses and their `asn` by mail host. `network.web` contains the requested host, `cname_chain`, addresses, `truncated` and `edge_provider`. The lookup does not add `www.` or test HTTP availability. A CDN or proxy can hide the origin.

`network.autonomous_systems` describes each ASN with `handle`, `name`, `country` and `type`. The country is the network registration country, not IP geolocation. Unknown attribution remains `null` or `unknown`. Network failures do not change the overall status or charge; inspect `network.meta` and `network.web.meta` separately.

With `variant=extended`, `registration` contains `registered_domain`, `registered_at`, `age_days`, `expires_at`, `registrar`, `statuses` and `meta`. Registry data describes the registrable parent of a subdomain. Missing registration dates make Extended partial; read `registration.meta.reason` for unavailable, unsupported or omitted data. In Standard, `registration` is `null`. Registration age does not establish company age or ownership.

## Use per-field metadata with the overall status

A profile has status `complete` or `partial`. Read each part’s `meta` for status, reason, source, observation and expiry times, and whether a value is stale. `meta.reason` explains why a value could not be established. Retrieval time must not replace the original observation time.

A `partial` profile can include usable routing while a secondary field is unavailable, stale or truncated. An `unknown` provider match or an unobserved catch-all state does not by itself mean the whole profile is partial. `complete` describes lookup coverage, not a positive verdict about the domain.

If the routing source fails, the endpoint can return `503 source_unavailable` rather than a guessed no-mail result. Keep request errors separate from the domain observations your application uses.

## Retry the same operation with the same key

Within 24 hours of completion, the same key, domain and variant return the saved response byte for byte. A replay does not refresh observations. Reusing a key with a different domain or variant produces `409 idempotency_conflict`. If the first attempt is still running, wait for its retry interval and repeat the same request and key.

A complete `standard` lookup costs 1 shared credit; a complete `extended` lookup costs 2. Extended costs 1 when the standard observations complete but the registration date is unavailable. Other partial results, saved-answer replays and confirmed refusals cost 0. Network enrichment does not affect the charge. A replay preserves `billing.operation_credits`; `X-Credits-Charged` reports the current request.

For `commit_unknown` or `accounting_uncertain`, the charge may already have committed. The response omits `X-Credits-Charged`; absence is not a confirmed zero. Repeat the request with the same key so it reaches the same operation. A new key creates new work.

## Choose the domain workflow you need

The [Domain Intelligence account page](https://emvero.io/domain-intelligence/) explains how to inspect the profile without writing code. If your only question is whether a domain is configured to receive mail, the free [email domain checker](https://emvero.io/email-domain-checker/) provides a narrower answer without an account.

For request validation, the full schema and error handling, use the [Domain Intelligence API guide](https://docs.emvero.io/using/domain-intelligence/). Neither domain workflow verifies a named mailbox or sends an email.

Questions

## Frequently asked.

**Which domain fields does the API return?**

The response includes routing, MX hosts and priorities, provider matching, disposable/public-provider signals, held catch-all state, SPF/DMARC, mail and web IP addresses, CNAMEs, CDN/proxy attribution and autonomous systems. Extended adds registration data. Each observation retains its source and state.

**Does a routable domain mean the mailbox exists?**

No. A route describes the domain. This lookup makes no SMTP probe and cannot establish a named mailbox, mailbox ownership or future inbox delivery.

**Does the lookup test whether a sender passes SPF or DMARC?**

It reads published records and supported syntax or policy fields. Their `evaluation` is `not_performed`. It does not evaluate a message, discover DKIM keys or recursively follow SPF includes.

**Can I use a partial profile?**

Read the status and metadata of the part you need. A `partial` result may retain a known route while another observation is unavailable or stale. An unknown catch-all state by itself does not necessarily make the whole profile partial.

**What do complete lookups and retries cost?**

A complete `standard` lookup costs 1 shared credit; a complete `extended` lookup costs 2. Extended costs 1 when the standard observations complete but the registration date is unavailable. Other partial results, saved-answer replays and confirmed refusals cost 0. Network enrichment does not affect the charge. A replay preserves `billing.operation_credits`; `X-Credits-Charged` reports the current request. For `commit_unknown` or `accounting_uncertain`, the charge is uncertain and that header is absent: retry the same key.

## Compared side by side

### MX record

An MX record is a DNS record that names a domain’s incoming mail server and its preference; it does not establish a mailbox.

Connect the domain lookup

## Use the profile in your backend or inspect it in your account.

Confirm a new account for 1,000 shared credits without a card. A complete Standard lookup costs 1 credit; Extended costs 2, or 1 when only its standard observations complete.

Start for free

View documentation
