The Yahoo check answers whether an e-mail address has a Yahoo Mail account. It covers yahoo.com, Yahoo's country domains and the older ymail.com and rocketmail.com addresses. It runs in bulk jobs and returns registered: true, false or null (unknown) for each address, with the time we checked. Nothing is sent to the address and no mailbox is read.
What does the Yahoo check tell you?
It tells you whether Yahoo has an account at the exact address you send. Yahoo Mail is one of the oldest free web mail services, and over the years it has handed out addresses under several domains. Customer databases therefore contain @yahoo.com, country versions like @yahoo.co.uk, @yahoo.fr or @yahoo.de, and the alternative @ymail.com and @rocketmail.com domains.
registered: true: a Yahoo account exists at this address.registered: false: a conclusive "no account".registered: null: no conclusive answer.statusandreasonsay why, and you are not charged.
Many Yahoo addresses were created years ago and never used again. Yahoo's own terms allow it to close accounts that stay inactive, so an address that worked in an old export may no longer exist. The check answers that question for today, and checked_at records when.
Who uses it, and why?
Yahoo addresses are common among long-standing consumers, which makes them important in older data and in some regional markets.
- Hygiene for older customer records. Before a service or account notice to existing customers, a batch run finds Yahoo addresses that no longer have an account. Updating them through another channel beats watching the message bounce.
- Deliverability. Large mailbox providers track how often a sender hits non-existent addresses. Removing dead Yahoo addresses protects delivery of receipts, alerts and password resets.
- Sign-up review. A nightly job over new sign-ups flags Yahoo addresses that never existed. That is a typical trait of scripted registrations. See OTP and sign-up fraud.
For a real-time answer while the user is on the form, use the mailbox check. To cover a whole list across providers, combine Yahoo with the Gmail and Outlook checks in one job.
What do you get back?
Each address becomes a row with kind: "email" and one entry per check in checks.
| Field | Type | Meaning |
|---|---|---|
email | string or null | Normalized address (trimmed, lowercased); null when invalid |
email_status | enum | valid, invalid_email, duplicate or suppressed |
checks["yahoo.email"].registered | boolean or null | true account exists, false none, null unknown |
…status | enum | completed, pending, unknown, unsupported_country or failed |
…reason | string or null | e.g. UPSTREAM_TIMEOUT |
…confidence, …checked_at | enum, timestamp | How sure the answer is, and when it was obtained |
…cached, …billed | boolean | Cache hit, and whether it was charged |
CSV and NDJSON downloads keep your original row order and add yahoo.email.status, yahoo.email.registered and yahoo.email.billed columns.
How is it billed?
You pay the bulk price per address with a conclusive answer. You're not charged for inconclusive results (unknown, unsupported country, timeout, invalid, duplicate). Run the free POST /v1/jobs/estimate first to see valid, duplicate and cached counts and the maximum cost, then pass that figure as max_cost. See pricing.
Repeat checks of the same address inside the freshness window can come from your account's cache. Cache hits are free.
What are the limits?
The Yahoo check is bulk only. POST /v1/lookup refuses it with 403 service_disabled ("The check 'yahoo.email' is available in bulk jobs only (POST /v1/jobs)."). A job takes up to 50,000 numbers and e-mails, as JSON or as a CSV upload with an email column.
- Up to 20 checks per request. Identifiers × applicable checks are capped at 100,000 per job.
- Requests that look like sequential number ranges or generated e-mail lists are rejected. Twenty or more addresses in one request on one domain whose local parts differ only by digits or separators are refused with
suspected_enumeration. Live keys are also limited to 50 addresses of one such pattern per account per UTC day. - Addresses are trimmed and lowercased, never rewritten.
- The daily cap counts e-mail addresses like numbers (see
GET /v1/limits).
How do I use it responsibly?
Check addresses from your own customers, users and leads, where you have a lawful reason to process them. We never open mailboxes and never send e-mail to the address. The answer is yes, no or unknown, and never includes personal details.
An existing account does not mean consent. Don't use the check to prepare unsolicited mailings, and don't test address variations to see whether someone has a Yahoo account. The acceptable use policy forbids both. People can object through the opt-out form. Suppressed addresses are skipped and never charged.
Example request
Test keys return fixed answers for test.mobilevalidate.com addresses (see test mode).
curl https://api.mobilevalidate.com/v1/jobs \
-H "Authorization: Bearer mv_test_publicSandboxn9ZgneuhR1B9CRfKG3fulym" \
-H "Content-Type: application/json" \
-d '{"emails":["[email protected]","[email protected]","[email protected]"],"checks":["yahoo"]}'// npm install mobilevalidate · Node.js 20+ · save as check.mjs and run: node check.mjs
import { MobileValidate } from "mobilevalidate";
// Omit apiKey to read MOBILEVALIDATE_API_KEY from the environment.
const mv = new MobileValidate({ apiKey: "mv_test_publicSandboxn9ZgneuhR1B9CRfKG3fulym" });
const { data, error } = await mv.jobs.create({
emails: [
"[email protected]",
"[email protected]",
"[email protected]",
],
checks: ["yahoo"],
});
if (error) console.error(error.code, error.message);
else console.dir(data, { depth: null });// Node.js 18+, Deno, Bun or the browser console (ES module: save as .mjs or use "type": "module").
const res = await fetch("https://api.mobilevalidate.com/v1/jobs", {
method: "POST",
headers: {
Authorization: "Bearer mv_test_publicSandboxn9ZgneuhR1B9CRfKG3fulym",
"Content-Type": "application/json",
},
body: JSON.stringify({
emails: [
"[email protected]",
"[email protected]",
"[email protected]",
],
checks: ["yahoo"],
}),
});
console.log(res.status, res.headers.get("x-request-id"));
console.dir(await res.json(), { depth: null });# pip install mobilevalidate-sdk
from mobilevalidate import MobileValidate
# Omit api_key to read MOBILEVALIDATE_API_KEY from the environment.
mv = MobileValidate(api_key="mv_test_publicSandboxn9ZgneuhR1B9CRfKG3fulym")
result = mv.jobs.create(
emails=[
"[email protected]",
"[email protected]",
"[email protected]",
],
checks=["yahoo"],
)
print(result)<?php
$ch = curl_init('https://api.mobilevalidate.com/v1/jobs');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer mv_test_publicSandboxn9ZgneuhR1B9CRfKG3fulym',
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'emails' => [
'[email protected]',
'[email protected]',
'[email protected]',
],
'checks' => ['yahoo'],
]),
]);
$response = curl_exec($ch);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL, $response, PHP_EOL;package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{"emails":["[email protected]","[email protected]","[email protected]"],"checks":["yahoo"]}`)
req, err := http.NewRequest("POST", "https://api.mobilevalidate.com/v1/jobs", body)
if err != nil {
panic(err)
}
req.Header.Set("Authorization", "Bearer mv_test_publicSandboxn9ZgneuhR1B9CRfKG3fulym")
req.Header.Set("Content-Type", "application/json")
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
out, _ := io.ReadAll(res.Body)
fmt.Println(res.Status, string(out))
}require "net/http"
require "json"
uri = URI("https://api.mobilevalidate.com/v1/jobs")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer mv_test_publicSandboxn9ZgneuhR1B9CRfKG3fulym"
req["Content-Type"] = "application/json"
req.body = JSON.generate({
"emails" => [
"[email protected]",
"[email protected]",
"[email protected]"
],
"checks" => ["yahoo"]
})
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
puts res.code, res.bodyRuns as pasted with the public sandbox key, which answers the test values only. In the SDKs, omit the key to use MOBILEVALIDATE_API_KEY.
Response of GET /v1/jobs/{id}/results (excerpt, test mode: the first item of data):
{
"kind": "email",
"input": "re•••@test.mobilevalidate.com",
"email": "[email protected]",
"email_status": "valid",
"e164": null,
"country": null,
"checks": {
"yahoo.email": {
"service": "yahoo.email",
"status": "completed",
"registered": true,
"attributes": null,
"confidence": "high",
"confidence_score": 0.99,
"checked_at": "2026-09-25T14:25:31.802Z",
"cached": false,
"age_seconds": 0,
"billed": false,
"reason": null,
"poll_after_ms": null
}
},
"test": true
}Try it now
Bulk-only service: create a job via POST /v1/jobs, then read GET /v1/jobs/{id}/results. Every example runs as pasted: it uses the public sandbox key, which answers the test values for free. In the SDKs, omit the key to use MOBILEVALIDATE_API_KEY.
curl https://api.mobilevalidate.com/v1/jobs \
-H "Authorization: Bearer mv_test_publicSandboxn9ZgneuhR1B9CRfKG3fulym" \
-H "Content-Type: application/json" \
-d '{"emails":["[email protected]"],"checks":["yahoo.email"]}'// npm install mobilevalidate · Node.js 20+ · save as check.mjs and run: node check.mjs
import { MobileValidate } from "mobilevalidate";
// Omit apiKey to read MOBILEVALIDATE_API_KEY from the environment.
const mv = new MobileValidate({ apiKey: "mv_test_publicSandboxn9ZgneuhR1B9CRfKG3fulym" });
const { data, error } = await mv.jobs.create({
emails: ["[email protected]"],
checks: ["yahoo.email"],
});
if (error) console.error(error.code, error.message);
else console.dir(data, { depth: null });// Node.js 18+, Deno, Bun or the browser console (ES module: save as .mjs or use "type": "module").
const res = await fetch("https://api.mobilevalidate.com/v1/jobs", {
method: "POST",
headers: {
Authorization: "Bearer mv_test_publicSandboxn9ZgneuhR1B9CRfKG3fulym",
"Content-Type": "application/json",
},
body: JSON.stringify({
emails: ["[email protected]"],
checks: ["yahoo.email"],
}),
});
console.log(res.status, res.headers.get("x-request-id"));
console.dir(await res.json(), { depth: null });# pip install mobilevalidate-sdk
from mobilevalidate import MobileValidate
# Omit api_key to read MOBILEVALIDATE_API_KEY from the environment.
mv = MobileValidate(api_key="mv_test_publicSandboxn9ZgneuhR1B9CRfKG3fulym")
result = mv.jobs.create(
emails=["[email protected]"],
checks=["yahoo.email"],
)
print(result)<?php
$ch = curl_init('https://api.mobilevalidate.com/v1/jobs');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer mv_test_publicSandboxn9ZgneuhR1B9CRfKG3fulym',
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'emails' => ['[email protected]'],
'checks' => ['yahoo.email'],
]),
]);
$response = curl_exec($ch);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL, $response, PHP_EOL;package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{"emails":["[email protected]"],"checks":["yahoo.email"]}`)
req, err := http.NewRequest("POST", "https://api.mobilevalidate.com/v1/jobs", body)
if err != nil {
panic(err)
}
req.Header.Set("Authorization", "Bearer mv_test_publicSandboxn9ZgneuhR1B9CRfKG3fulym")
req.Header.Set("Content-Type", "application/json")
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
out, _ := io.ReadAll(res.Body)
fmt.Println(res.Status, string(out))
}require "net/http"
require "json"
uri = URI("https://api.mobilevalidate.com/v1/jobs")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer mv_test_publicSandboxn9ZgneuhR1B9CRfKG3fulym"
req["Content-Type"] = "application/json"
req.body = JSON.generate({
"emails" => ["[email protected]"],
"checks" => ["yahoo.email"]
})
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
puts res.code, res.body// .mcp.json (Claude Code), ~/.cursor/mcp.json (Cursor) or .vscode/mcp.json ("servers" instead of "mcpServers")
{
"mcpServers": {
"mobilevalidate": {
"type": "http",
"url": "https://mcp.mobilevalidate.com/mcp",
"headers": { "Authorization": "Bearer ${MOBILEVALIDATE_API_KEY}" }
}
}
}
// Then ask your agent, e.g.:
// "Check [email protected] with yahoo.email" → tool: create_lookup_jobThe hosted MCP server is live for customers with an agent key (mv_agent_…) or a test key. Or run it locally with npx -y @mobilevalidate/mcp.
Real test-mode result for this check
{
"service": "yahoo.email",
"status": "completed",
"registered": true,
"attributes": null,
"confidence": "high",
"confidence_score": 0.99,
"checked_at": "2026-09-25T14:25:29.021Z",
"cached": false,
"age_seconds": 0,
"billed": false,
"reason": null,
"poll_after_ms": null
}What you get
Fields of checks["yahoo.email"], generated from the public service catalog.
| Field | Type | Meaning |
|---|---|---|
| registered | boolean | null | true = found, false = not found, null = unknown (not charged). |
| status | enum | completed, pending, unknown, unsupported_country or failed. |
| checked_at | timestamp | When the answer was obtained. |
Frequently asked questions
Which domains belong to Yahoo Mail?
yahoo.com and Yahoo's country domains (for example yahoo.co.uk or yahoo.fr), plus the older ymail.com and rocketmail.com addresses that Yahoo Mail still serves. Send them all to the Yahoo check.
Does the check send an e-mail or open the mailbox?
No. Nothing is sent to the address and no mailbox is opened or read. The answer is yes, no or unknown, never a name, avatar or profile.
Why is the Yahoo check only in bulk jobs?
The Yahoo check is offered in bulk jobs only for now. POST /v1/lookup refuses it with service_disabled; use POST /v1/jobs. For real-time checks at sign-up, use the mailbox check (email).
What does an unknown answer cost?
Nothing. Unknown answers have registered set to null and are not charged, like every other inconclusive result.

