Free Email APIs in 2026: Validation, Forwarding, and Disposable Inboxes
"Free email API" means five different things depending on what you're building. If you're sending transactional mail, you want a delivery API. If you're cleaning a signup form, you want validation. If you're testing a signup flow end to end, you want a disposable inbox you can read programmatically. If you're running a small SaaS on a custom domain, you want forwarding.
This guide covers the four categories that genuinely have free, no-credit-card options in 2026: validation, disposable-address detection, domain forwarding, and programmable temporary inboxes. Sending is the one category where free tiers have largely collapsed — we'll cover why at the end, and what your realistic options are.
Every API below is one you can hit with curl in the next sixty seconds. No sales call, no "contact us for pricing."
Quick comparison
| API | Category | Auth required | Free tier | Best for |
|---|---|---|---|---|
| Disify | Disposable detection | No | Unlimited (fair use) | Blocking throwaway signups |
| MailboxValidator | Deep validation | API key | 100 verifications/mo | SMTP-level list hygiene |
| ImprovMX | Forwarding | API key | 1 domain, 25 aliases | Custom-domain support inboxes |
| Mail.tm | Temporary inbox | JWT (self-serve) | Free, rate-limited | Automated E2E signup tests |
| Guerrilla Mail | Temporary inbox | No | Free, session-based | Quick throwaway addresses |
Why email validation is the highest-ROI free API
Before you spend anything on email infrastructure, understand where the money leaks. A typical B2C signup form collects three kinds of bad addresses:
- Typos —
gmial.com,hotmial.com,yahooo.com. Roughly 1–3% of hand-typed addresses. - Disposable addresses — throwaway inboxes used to farm free trials, claim referral bonuses, or dodge your onboarding sequence.
- Dead mailboxes — addresses that existed once and now hard-bounce.
Each category costs you differently. Typos cost you a customer who never gets their confirmation email. Disposables cost you trial abuse and inflated MAU numbers. Dead mailboxes cost you sender reputation — and once your bounce rate crosses roughly 2%, mailbox providers start routing your legitimate mail to spam.
The important insight: the first two categories are solvable for free. Category three requires SMTP-level verification, which costs real money at scale because someone has to run the infrastructure that opens connections to remote mail servers.
So the pragmatic architecture is a two-tier check — free API on every signup, paid verification only for the addresses that matter.
Disify: unauthenticated disposable-domain detection
Disify is the simplest useful email API in existence. No signup, no key, no rate-limit header to parse. You GET a URL and get JSON back.
curl https://disify.com/api/email/user@mailinator.com
{
"format": true,
"domain": "mailinator.com",
"disposable": true,
"dns": true
}
Four booleans, each answering a distinct question:
format— does the address parse as a valid RFC-compliant email?domain— the extracted domain, echoed backdisposable— is this domain on the known-throwaway list?dns— does the domain have MX records? (A domain with no MX cannot receive mail at all)
That dns field is underrated. It catches every typo'd domain that doesn't happen to be a real registered mail host — gmial.com variants included, provided nobody has squatted them with MX records.
Here's a production-shaped Next.js API route wrapping it:
// pages/api/validate-email.js
const DISIFY_TIMEOUT_MS = 2000;
export default async function handler(req, res) {
const { email } = req.body;
if (!email || typeof email !== 'string') {
return res.status(400).json({ error: 'email required' });
}
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), DISIFY_TIMEOUT_MS);
try {
const r = await fetch(
`https://disify.com/api/email/${encodeURIComponent(email)}`,
{ signal: controller.signal }
);
if (!r.ok) throw new Error(`disify ${r.status}`);
const data = await r.json();
return res.status(200).json({
valid: data.format && data.dns && !data.disposable,
reasons: {
malformed: !data.format,
noMailServer: !data.dns,
disposable: data.disposable,
},
});
} catch (err) {
// Fail open: never block a signup because a free API was slow.
return res.status(200).json({ valid: true, degraded: true });
} finally {
clearTimeout(timer);
}
}
Two decisions in that snippet are worth calling out, because they're the ones people get wrong.
Fail open, not closed. Disify is a free service with no SLA. If it's down or slow, blocking every signup on your site is a far worse outcome than admitting a few throwaway addresses. The degraded: true flag lets you log it and re-check asynchronously later.
Hard timeout. Two seconds is generous for a single JSON lookup, and it caps the damage when the upstream hangs rather than erroring. Without AbortController, a stalled fetch can hold your function open until the platform timeout — which on most serverless hosts is now measured in minutes, not seconds.
Disify also exposes a bulk endpoint. POST a newline-separated list as form data and get aggregate counts back:
curl -X POST https://disify.com/api/email/mass \
-d "emails=a@gmail.com%0Ab@mailinator.com%0Ac@guerrillamail.com"
Useful for auditing an existing list before you import it into an ESP. Be reasonable about batch sizes — this is a free service running on someone's goodwill, and the fastest way to lose a free email API is for everyone to hammer it.
The limits of blocklist-based detection
Disposable-domain lists are a treadmill. New throwaway domains appear daily; any list is a snapshot. Expect roughly 80–90% coverage of casual disposable use and considerably less against someone deliberately evading you with a freshly registered domain.
That's fine for the actual job. You're not building an unbreakable gate — you're raising the cost of abuse above the value of whatever you're giving away free. If your free tier is worth $5, you only need to make evasion cost more than $5 of effort.
MailboxValidator: SMTP verification when booleans aren't enough
Blocklists tell you whether a domain is throwaway. They can't tell you whether a mailbox exists. jane.doe.2019@gmail.com passes every format and DNS check and may still hard-bounce.
MailboxValidator closes that gap by doing SMTP-level verification — connecting to the recipient's mail server and probing whether the mailbox accepts mail, without actually delivering anything.
curl "https://api.mailboxvalidator.com/v2/validation/single?email=test@example.com&key=YOUR_API_KEY&format=json"
The response is considerably richer than Disify's four booleans:
{
"email_address": "test@example.com",
"domain": "example.com",
"is_free": "False",
"is_syntax": "True",
"is_domain": "True",
"is_smtp": "True",
"is_verified": "True",
"is_server_down": "False",
"is_greylisted": "False",
"is_disposable": "False",
"is_suppressed": "False",
"is_role": "False",
"is_high_risk": "False",
"is_catchall": "False",
"mailboxvalidator_score": 0.85,
"status": "True",
"credits_available": 96
}
Note the fields return strings, not JSON booleans — "True", not true. This trips up nearly everyone on first integration, because if (result.is_disposable) is truthy for the string "False". Normalize at the boundary:
const toBool = (v) => v === 'True';
async function verifyEmail(email) {
const url = new URL('https://api.mailboxvalidator.com/v2/validation/single');
url.searchParams.set('email', email);
url.searchParams.set('key', process.env.MAILBOXVALIDATOR_KEY);
url.searchParams.set('format', 'json');
const r = await fetch(url);
const d = await r.json();
return {
deliverable: toBool(d.is_verified) && !toBool(d.is_server_down),
disposable: toBool(d.is_disposable),
roleAccount: toBool(d.is_role), // info@, support@, admin@
catchAll: toBool(d.is_catchall), // domain accepts everything — verdict is inconclusive
freeProvider: toBool(d.is_free), // gmail, yahoo, outlook
score: parseFloat(d.mailboxvalidator_score),
creditsLeft: parseInt(d.credits_available, 10),
};
}
Three fields deserve interpretation rather than a naive boolean check:
is_catchall — a catch-all domain accepts mail to every address, so SMTP verification proves nothing. Treat catch-all results as unknown, not valid. Many corporate domains are catch-all.
is_role — role accounts (support@, info@, sales@) are real and deliverable but often shouldn't go into a marketing list. They're read by rotating staff, get marked as spam more often, and in some jurisdictions carry different consent expectations. Deliverable ≠appropriate.
is_greylisted — greylisting temporarily rejects first-contact connections by design. A greylisted result means "try again later," not "invalid."
The free tier is 100 verifications per month. That is not a signup-form budget. It's a budget for the tier-two check in a layered design:
async function validateSignup(email) {
// Tier 1: free, unlimited, fast — runs on every signup
const basic = await disifyCheck(email);
if (!basic.valid) {
return { accept: false, reason: basic.reasons };
}
// Tier 2: metered — only for addresses that will cost you money
if (await isHighValueSignup(email)) {
const deep = await verifyEmail(email);
if (!deep.deliverable && !deep.catchAll) {
return { accept: false, reason: 'undeliverable' };
}
}
return { accept: true };
}
Define "high value" by what a bad address actually costs you: paid-plan signups, users entering a long onboarding drip, addresses being imported in bulk. Everything else gets the free check and a confirmation email, which is itself a deliverability test that costs you nothing extra.
ImprovMX: free email forwarding on your own domain
Different problem, same category. You have a domain and you want support@yourdomain.com to land in an inbox you already read — but you don't want a $6/user/month mailbox for an alias that gets four emails a week.
ImprovMX does exactly that: point your domain's MX records at their servers, define aliases, and mail forwards to any destination. The free tier covers one domain and 25 aliases, which is more than enough for a side project or a small SaaS.
Setup is DNS plus one API call. First the MX records:
yourdomain.com. MX 10 mx1.improvmx.com.
yourdomain.com. MX 20 mx2.improvmx.com.
Then create aliases programmatically. Auth is HTTP Basic with api as the username and your key as the password:
curl -X POST "https://api.improvmx.com/v3/domains/yourdomain.com/aliases/" \
-u "api:$IMPROVMX_KEY" \
-H "Content-Type: application/json" \
-d '{"alias": "support", "forward": "you@gmail.com"}'
The programmatic angle is what makes this an API rather than a settings page. A common pattern is per-customer forwarding addresses, so inbound mail is automatically attributable:
const IMPROVMX = 'https://api.improvmx.com/v3';
const auth = 'Basic ' + Buffer.from(`api:${process.env.IMPROVMX_KEY}`).toString('base64');
async function createCustomerAlias(customerId, destination) {
const r = await fetch(`${IMPROVMX}/domains/${process.env.MAIL_DOMAIN}/aliases/`, {
method: 'POST',
headers: { Authorization: auth, 'Content-Type': 'application/json' },
body: JSON.stringify({
alias: `cust-${customerId}`,
forward: destination,
}),
});
if (!r.ok) {
const err = await r.json().catch(() => ({}));
throw new Error(`ImprovMX ${r.status}: ${JSON.stringify(err)}`);
}
return r.json();
}
A wildcard alias (*) catches everything not matched by a specific rule, which is how you build anything@yourdomain.com addresses without pre-registering them.
Two constraints to plan around. Forwarding is inbound only on the free tier — sending from your domain through ImprovMX (SMTP) is a paid feature, so replies go out from whatever the destination mailbox is. And forwarded mail inherits the original sender's SPF alignment, which means aggressive receiving filters occasionally treat forwarded mail as suspicious. For a support inbox this is a non-issue; for high-volume automated mail, use a proper sending provider.
Mail.tm and Guerrilla Mail: programmable inboxes for testing
The last category flips the perspective. Instead of validating addresses other people give you, you need a real, readable inbox that your test suite can create on demand — to verify that your signup email actually arrives, that the confirmation link works, and that the password reset flow completes end to end.
Mail.tm is the better-designed of the two: a proper REST API with JWT auth, JSON responses, and a stable message schema. The flow is create-account → get-token → poll-messages.
const API = 'https://api.mail.tm';
async function createTestInbox() {
// 1. Pick an available domain
const domains = await fetch(`${API}/domains`).then(r => r.json());
const domain = domains['hydra:member'][0].domain;
const address = `test-${Date.now()}@${domain}`;
const password = crypto.randomUUID();
// 2. Create the account
await fetch(`${API}/accounts`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ address, password }),
});
// 3. Exchange credentials for a JWT
const { token } = await fetch(`${API}/token`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ address, password }),
}).then(r => r.json());
return { address, token };
}
async function waitForMessage(token, { timeoutMs = 30000, intervalMs = 3000 } = {}) {
const deadline = Date.now() + timeoutMs;
const headers = { Authorization: `Bearer ${token}` };
while (Date.now() < deadline) {
const res = await fetch(`${API}/messages`, { headers });
const list = await res.json();
const messages = list['hydra:member'] || [];
if (messages.length > 0) {
// List view is a summary; fetch the full message for the body
const full = await fetch(`${API}/messages/${messages[0].id}`, { headers });
return full.json();
}
await new Promise(r => setTimeout(r, intervalMs));
}
throw new Error('No message received before timeout');
}
The response envelope uses Hydra/JSON-LD conventions, hence hydra:member rather than a plain array. Message objects include subject, from, text, html, and intro — the full text body is what you want for extracting confirmation links:
const msg = await waitForMessage(token);
const link = msg.text.match(/https:\/\/[^\s<>"]+\/confirm\/[A-Za-z0-9_-]+/)?.[0];
Guerrilla Mail solves the same problem with a much older interface — a single endpoint with a f (function) query parameter and session state in a cookie:
curl "https://api.guerrillamail.com/ajax.php?f=get_email_address"
# → {"email_addr":"abc123@guerrillamailblock.com","sid_token":"...", ...}
curl "https://api.guerrillamail.com/ajax.php?f=check_email&seq=0&sid_token=YOUR_TOKEN"
Guerrilla Mail's advantage is zero setup — one request and you have an address. Its disadvantages are the awkward RPC-style interface, a session-bound token you must thread through every call, and heavy blocklisting: because it's been the canonical throwaway service for over a decade, many sites (possibly including the one you're testing) reject its domains outright.
Recommendation: use Mail.tm for automated tests where you're driving the API from code, and Guerrilla Mail for quick manual throwaway needs. Poll on a 2–5 second interval with a hard timeout; both services rate-limit, and a tight polling loop across a parallel CI matrix will get you throttled fast.
One caveat that matters more than the API design: these are public inboxes. Anyone who guesses the address can read it. Never use them for anything touching real credentials, real customer data, or production systems. They're for testing your own flows against your own staging environment.
What about free sending APIs?
This is what most people actually search for, so let's be direct: free tiers for transactional sending have shrunk considerably. The economics are unforgiving — sending providers absorb the reputation cost of every spammer who signs up for a free tier, so the industry has converged on small, verification-gated allowances rather than generous free plans.
What that means practically:
- Expect free tiers in the range of a few thousand emails per month, typically requiring domain verification (SPF and DKIM records) before you can send to anyone but yourself.
- Sandbox modes that only send to pre-verified addresses are common and are genuinely useful for development.
- "Free forever, no card" transactional sending at meaningful volume is largely gone. Budget for it.
Check current limits directly with each provider before you architect around a number — free tiers change without much announcement, and a figure quoted in a blog post is stale the month after it's published.
The free email APIs in this guide are complements to sending, not substitutes for it. Validation reduces bounces, which protects the sender reputation that determines whether your paid sending works at all. Forwarding handles inbound so you don't pay for mailboxes. Temporary inboxes let you test the whole pipeline without touching production.
Putting it together
A complete email stack for a small product, using free tiers where they hold up:
| Layer | Tool | Cost |
|---|---|---|
| Signup validation | Disify (format + DNS + disposable) | Free |
| Deep verification | MailboxValidator on high-value signups | Free to 100/mo |
| Inbound support mail | ImprovMX forwarding | Free (1 domain) |
| E2E test inboxes | Mail.tm in CI | Free |
| Transactional sending | Paid provider | Budget for it |
Four of five layers cost nothing, and the fifth is the one where paying is genuinely the correct engineering decision.
The pattern worth internalizing: free email APIs are excellent at the edges of your email system — checking what comes in, routing what arrives, testing what goes out. They're not a replacement for the core sending path, and treating them as one is how you end up with a deliverability problem that costs far more to fix than the subscription you avoided.
Start with Disify on your signup form today. It takes one API route, no account, and will immediately catch a category of bad data you're currently accepting.
Frequently asked questions
Is there a truly free email API with no signup? Yes — Disify requires no account or API key for validation and disposable detection, and Guerrilla Mail requires none for temporary inboxes. Both are fair-use services without SLAs, so build in timeouts and fail-open behavior.
Can a free email API tell me if an address really exists? Only partially. Format and MX-record checks are free and catch typos and dead domains. Confirming that a specific mailbox exists requires SMTP verification, which is metered everywhere — MailboxValidator's free tier gives you 100 checks a month. Catch-all domains defeat mailbox verification entirely regardless of what you pay.
Will validating emails hurt my signup conversion? Not if you fail open and validate asynchronously where possible. Block only on unambiguous failures (malformed syntax, no MX records) and treat everything else as a soft signal. Never let a third-party API outage become a signup outage.
Are temporary email APIs safe to use in CI? For testing your own flows against staging, yes. The inboxes are publicly readable by anyone who knows the address, so never route real credentials, production data, or anything sensitive through them.
How accurate is disposable-domain detection? Blocklists catch most casual throwaway use but lag behind newly registered domains. Treat it as raising the cost of abuse rather than an absolute gate — combine it with confirmation emails and rate limiting for meaningful protection.