mailintel
Reference

HTTP API

The same resolver as the library, exposed as a free JSON endpoint. No key, no account, CORS open to any origin. Built for scripts, agents and anything that isn't JavaScript.

GEThttps://mailintel.atef.dev/api/lookup?q=[email protected]

Parameters

qstring

Email address or domain. Required unless email or domain is used.

emailstring

Alias for q, kept for readability.

domainstring

Alias for q. Accepts a bare domain such as acme.dev.

Examples

curl
curl "https://mailintel.atef.dev/api/[email protected]"
javascript
const res = await fetch(
  "https://mailintel.atef.dev/api/lookup?q=" + encodeURIComponent("[email protected]"),
);
const { result, meta } = await res.json();

console.log(result.provider);          // "google"
console.log(result.connection.smtp);   // { host, port, security }
console.log(meta.elapsedMs);           // 214
python
import requests

r = requests.get(
    "https://mailintel.atef.dev/api/lookup",
    params={"q": "[email protected]"},
    timeout=10,
)
r.raise_for_status()
print(r.json()["result"]["connection"]["imap"])

Response

The payload wraps the library result with a small meta object. The result shape is identical to mailintel().

200 OK
{
  "result": {
    "email": "[email protected]",
    "domain": "acme.dev",
    "provider": "google",
    "providerDisplayName": "Google Workspace",
    "mx": "smtp.google.com",
    "type": "business",
    "isFree": false,
    "hasMx": true,
    "connection": {
      "imap": { "host": "imap.gmail.com", "port": 993, "security": "tls" },
      "smtp": { "host": "smtp.gmail.com", "port": 465, "security": "tls" },
      "username": "[email protected]",
      "usernameTemplate": "%EMAILADDRESS%"
    },
    "status": "ok",
    "confidence": "high",
    "source": "mx-lookup",
    "raw": { "mx": [], "dns": {}, "ispdb": null }
  },
  "meta": {
    "elapsedMs": 214,
    "resolver": "cloudflare",
    "at": "2026-10-29T14:02:11.000Z",
    "disposable": false
  }
}

note connection is null whenever status isn't ok. Always branch on status before reading hosts.
meta.disposable is a heuristic from a curated temporary-email list — useful as a signal, never as proof.

Errors

400

The input is not a valid email address or domain.

429

More than 60 requests in a minute from one IP. Respect Retry-After.

502

The DNS or ISPDB upstream failed. Retry with backoff.

Limits & caching

  • Rate limit. 60 requests per minute per IP. Fair use — no key, no quota to buy.

  • CDN cache. Successful results are cached for 30 minutes and served stale for a day while revalidating.

  • Per-instance cache. The resolver also keeps a 30-minute in-memory cache per lambda instance.

  • Privacy. Application code stores only aggregate domain-level counters. Use ?domain= instead of ?q= to keep the local part out of the request URL.

Self-hosting

The endpoint is a Next.js route handler with no database. In your own app, call the library directly — it runs on Node, Bun, Deno, Vercel, Cloudflare Workers and the browser.

app/api/lookup/route.ts
import { NextResponse } from "next/server";
import { createMailintel } from "mailintel";

const lookup = createMailintel({ timeout: 5000 });

export async function GET(request: Request) {
  const q = new URL(request.url).searchParams.get("q") ?? "";
  const result = await lookup(q);
  return NextResponse.json({ result }, {
    headers: { "access-control-allow-origin": "*" },
  });
}

Prefer it in-process?

The library has no network limit and no rate limit.

Library docs →