JSON Schema Validation for Email Fields: Complete Guide
Use json schema validation email fields correctly: validate format, handle empty values, add custom rules, and know when to verify deliverability.

json schema validation email fields is the right first layer for API safety. It tells you whether the payload contains a string that looks like an email address. It does not tell you whether that address can receive mail.
How JSON Schema validates email fields
JSON Schema validates email fields by checking that a value is a string and, if enabled, that it matches the schema’s email format.
The common pattern is:
{
"type": "object",
"properties": {
"email": {
"type": "string",
"format": "email"
}
},
"required": ["email"]
}
That gives you two checks:
type: "string"rejects numbers, booleans, arrays, objects, andnull.format: "email"asks the validator to check email-like syntax.
This is the usual json schema email format pattern. You will also see it described as json schema format email or JSON schema email validation.
But the important limit is this:
JSON Schema checks structure. It does not prove that a mailbox exists, accepts mail, or belongs to a real user.
For example, this can pass JSON Schema validation:
nobody@example.com
It has a valid shape. But it may not be a real mailbox. The domain may not accept mail. The mailbox may not exist. The address may be disposable. The receiving server may accept all addresses and bounce later.
Validator behavior also differs. In some JSON Schema libraries, format is an annotation by default. In others, it can be enforced, disabled, or moved into a separate plugin. You must check your validator and configuration before you rely on it.
Do not assume format: "email" runs in production just because your schema contains it. Write a failing test with an invalid email and confirm your validator rejects it.
Basic JSON Schema examples for email fields
You can model most API email fields with a small set of schema patterns.
Required email field
Use this for signup forms, account creation, checkout accounts, and any payload where email is mandatory.
{
"type": "object",
"additionalProperties": false,
"properties": {
"email": {
"type": "string",
"format": "email",
"maxLength": 254
}
},
"required": ["email"]
}
maxLength: 254 is a practical guardrail. It matches the commonly accepted maximum length for email addresses and prevents oversized input from reaching your application code.
Optional email field
Use this when the field can be absent.
{
"type": "object",
"properties": {
"email": {
"type": "string",
"format": "email",
"maxLength": 254
}
}
}
Here, email is valid if omitted. If present, it must be a string in email format.
Nullable email field
If your API uses null to mean “no email,” allow it explicitly.
{
"type": "object",
"properties": {
"email": {
"type": ["string", "null"],
"format": "email",
"maxLength": 254
}
}
}
Be careful here. Some validators only apply format when the value is a string. That is usually what you want.
Empty string email field
Avoid empty strings if you control the API. Prefer omitted fields or null.
If you must support empty strings from a legacy form, model them clearly:
{
"type": "object",
"properties": {
"email": {
"anyOf": [
{
"type": "string",
"format": "email",
"maxLength": 254
},
{
"const": ""
}
]
}
}
}
This makes the behavior explicit. An empty string is allowed, but only because you chose to allow it.
Array of email addresses
Use an array for invites, recipients, approvers, or notification settings.
{
"type": "object",
"properties": {
"recipients": {
"type": "array",
"minItems": 1,
"maxItems": 50,
"uniqueItems": true,
"items": {
"type": "string",
"format": "email",
"maxLength": 254
}
}
},
"required": ["recipients"]
}
uniqueItems: true helps, but it is exact-value matching. It will not treat User@Example.com and user@example.com as duplicates unless you normalize before validation or before storage.
Common API payload patterns
For a signup form, keep the schema strict:
{
"type": "object",
"additionalProperties": false,
"properties": {
"email": { "type": "string", "format": "email", "maxLength": 254 },
"password": { "type": "string", "minLength": 12 }
},
"required": ["email", "password"]
}
For an invite form, validate the sender and recipients:
{
"type": "object",
"properties": {
"fromEmail": { "type": "string", "format": "email" },
"invitees": {
"type": "array",
"items": { "type": "string", "format": "email" },
"minItems": 1,
"maxItems": 100
}
},
"required": ["fromEmail", "invitees"]
}
For a lead form, email may be required, while phone and company remain optional:
{
"type": "object",
"properties": {
"email": { "type": "string", "format": "email" },
"company": { "type": "string", "maxLength": 120 },
"source": { "type": "string", "maxLength": 80 }
},
"required": ["email"]
}
These examples validate payload shape. They do not validate business quality or deliverability.
Common mistakes with JSON Schema email validation
Most production issues come from treating syntax validation as complete email validation.
Relying on regex alone
Email regexes look simple until they fail real users.
A basic regex may reject valid addresses with plus tags, subdomains, longer TLDs, quoted local parts, or internationalized domains. A very loose regex may accept obvious junk.
This is the practical difference in email regex vs JSON schema:
| Approach | Good for | Weakness |
|---|---|---|
| Custom regex | Simple UI hints | Easy to make too strict or too loose |
JSON Schema format: "email" | Standard API shape validation | Validator behavior varies |
| Email verification | Deliverability and risk decisions | Requires a network/API check |
Use JSON Schema for structure. Avoid inventing a complex regex unless you have a narrow internal requirement.
Assuming format: "email" is always enforced
This mistake is common with JavaScript validators.
Some validators require a formats package. Some treat format as metadata. Some let you disable strict format checking for performance or compatibility.
Add tests like these:
[
{ "email": "not-an-email" },
{ "email": "@example.com" },
{ "email": "user@" },
{ "email": "user@example.com" }
]
The first three should fail. The last one should pass schema validation.
Rejecting valid addresses with overly strict rules
Do not block addresses just because they include:
- A
+tag, such asalex+trial@example.com - A subdomain, such as
alex@mail.example.co.uk - A newer or longer top-level domain
- Uppercase characters
- A hyphen in the domain
You can normalize case for comparison, but do not over-normalize the local part. Domain names are case-insensitive. Local parts are technically case-sensitive, even though most major providers treat them as case-insensitive.
Accepting syntactically valid but undeliverable emails
This address can pass format: "email":
made-up-mailbox@real-company-domain.com
It may still bounce. JSON Schema does not check MX records. It does not ask the receiving mail server whether the mailbox exists. It does not detect catch-all behavior. It does not know whether the domain is disposable.
That gap matters when you send password resets, onboarding emails, sales sequences, invoices, or product invites.
Forgetting normalization and typo handling
Normalize before you validate and store:
- Trim leading and trailing whitespace.
- Convert the domain to lowercase.
- Convert obvious Unicode domain input to a consistent representation if your stack supports it.
- Deduplicate after normalization.
- Suggest fixes for common domain typos, such as
gmial.comtogmail.com.
Typo handling is not the same as validation. Treat it as a correction step. Ask the user to confirm the fixed address.
Using JSON Schema email validation with Ajv and other validators
With Ajv, email format validation usually requires adding the formats package and enabling format checks.
For Ajv v7 and v8, install ajv-formats:
npm install ajv ajv-formats
Then configure validation:
const ajv = new Ajv({ allErrors: true });
addFormats(ajv);
const schema = {
type: "object",
additionalProperties: false,
properties: {
email: {
type: "string",
format: "email",
maxLength: 254
}
},
required: ["email"]
};
const validate = ajv.compile(schema);
console.log(validate({ email: "user@example.com" })); // true
console.log(validate({ email: "not-an-email" })); // false
console.log(validate.errors);
That is the core of Ajv email format validation.
If you use another validator, check three things:
- Does it support the JSON Schema draft you use?
- Does it enforce
format: "email"by default? - Does it use the same email format behavior in frontend and backend code?
Server-side validation should be the source of truth. Frontend validation improves UX, but users can bypass it. Mobile clients can lag behind. Browser extensions can alter requests. Your API must reject invalid payloads on its own.
For consistent validation between frontend and backend:
- Share schema files where practical.
- Pin validator versions.
- Run the same test cases in both environments.
- Avoid adding stricter frontend-only email rules.
- Return machine-readable error codes from the API.
Test edge cases before shipping:
valid:
user@example.com
user.name+tag@example.co.uk
USER@EXAMPLE.COM
invalid:
plainaddress
user@
@example.com
user example@example.com
user@example
You do not need to accept every obscure RFC-valid address. You do need predictable behavior that matches your product requirements.
JSON Schema vs real email verification
JSON Schema validation and real email verification answer different questions.
JSON Schema asks: “Does this field look like an email address in a valid payload?”
Email verification asks: “Should I trust this address enough to send to it?”
| Check | JSON Schema format: "email" | Email verification |
|---|---|---|
| Field is present | Yes, with required | No |
| Value is a string | Yes | No |
| Email-like syntax | Yes, if format is enforced | Yes |
| Domain has mail records | No | Yes |
| Mailbox appears reachable | No | Often, via SMTP probing |
| Disposable domain detection | No | Yes |
| Catch-all detection | No | Yes |
| Role account detection | No | Often |
| Typo suggestions | No | Often |
| Bounce risk scoring | No | Yes |
A valid JSON Schema email can still bounce because deliverability depends on systems outside your payload:
- The domain may not have valid MX records.
- The mailbox may not exist.
- The domain may accept all recipients and later drop or bounce mail.
- The address may be disposable.
- The recipient server may reject mail from your sending infrastructure.
- The user may have mistyped a real domain.
Call an email field validation API after schema validation when the email affects revenue, authentication, sender reputation, or workflow quality.
Good places to verify:
- During signup, before sending a confirmation email
- Before creating sales leads
- Before sending product invites
- Before importing a CSV into your CRM or ESP
- Before launching a lifecycle or cold outreach campaign
A verification result might look like this:
{
"email": "alex@example.com",
"verdict": "risky",
"riskScore": 62,
"checks": {
"syntax": true,
"mx": true,
"smtp": "unknown",
"disposable": false,
"catchAll": true,
"role": false
},
"suggestion": null
}
That gives your application more than pass/fail. You can route risky addresses differently.
A production-ready email validation flow
A production flow should separate payload correctness from deliverability decisions.
Step 1: normalize input
Normalize before validation where safe:
function normalizeEmailInput(value) {
if (typeof value !== "string") return value;
const trimmed = value.trim();
const at = trimmed.lastIndexOf("@");
if (at === -1) return trimmed;
const local = trimmed.slice(0, at);
const domain = trimmed.slice(at + 1).toLowerCase();
return `${local}@${domain}`;
}
Do not blindly lowercase the full address unless your business rules allow it. Lowercase the domain. Be cautious with the local part.
Step 2: validate JSON payload shape with JSON Schema
Run your schema validator next. Reject malformed payloads early.
This protects your application from bad types, missing fields, oversized strings, extra properties, and structurally invalid email fields.
Step 3: verify deliverability with an email verification API
After the schema passes, call email deliverability validation for addresses that matter.
This is where a service such as Bounceable fits. It can check deliverability signals, disposable domains, catch-all behavior, role accounts, typo suggestions, and bounce risk before you send.
Step 4: store verdicts and risk metadata
Store the verification result with the email record:
{
"email": "alex@example.com",
"emailStatus": "risky",
"emailRiskScore": 62,
"emailRiskReasons": ["catch_all"],
"emailVerifiedAt": "2026-06-13T12:00:00Z"
}
This helps support, analytics, campaign routing, and auditability. It also prevents repeated verification calls for the same unchanged address.
Step 5: decide whether to accept, warn, block, or request correction
Do not treat every non-deliverable signal the same.
Use clear policy:
| Verdict | Suggested action |
|---|---|
| Deliverable | Accept and proceed |
| Risky | Accept with warning, suppress from campaigns, or route for review |
| Undeliverable | Block or request a different email |
| Unknown | Allow for low-risk flows; require confirmation for high-risk flows |
A password reset flow should be strict. A newsletter preference form can be more forgiving. A bulk outbound campaign should be stricter because bounces affect sender reputation.
Recommended validation rules by use case
Different forms need different email validation rules. Use the same primitives, but change the policy.
Signup forms
For signup forms, validate in real time and suggest corrections.
Recommended rules:
- Trim whitespace.
- Validate with JSON Schema on the server.
- Run real-time verification before sending confirmation mail.
- Show typo suggestions for common domains.
- Block clearly undeliverable or disposable addresses if they create abuse.
- Let the user correct the address before account creation or before activation.
Keep the error copy specific:
This email address looks misspelled. Did you mean alex@gmail.com?
That works better than:
Invalid email.
Lead capture
For lead capture, avoid throwing away every risky address automatically.
Recommended rules:
- Require a syntactically valid email.
- Verify deliverability after submit.
- Accept risky addresses, but route them differently.
- Flag disposable, role, and free-provider addresses if sales quality matters.
- Suppress undeliverable addresses from automated sequences.
A risky lead may still be useful. A catch-all corporate domain can hide a real buyer. Route based on risk instead of blocking too aggressively.
Invitations
For invitations, check deliverability before sending.
Recommended rules:
- Validate every invitee address in the array.
- Deduplicate normalized addresses.
- Verify each recipient.
- Block undeliverable recipients before sending.
- Warn the sender about risky or catch-all recipients.
- Log who invited whom and when.
This prevents wasted invites and confusing “I never got it” support tickets.
Bulk imports
For bulk imports, verify before campaigns.
Recommended rules:
- Validate CSV shape first.
- Normalize and deduplicate addresses.
- Batch verify the list before adding it to active sending segments.
- Suppress undeliverable and disposable addresses.
- Segment risky and unknown addresses for lower-volume testing or manual review.
- Store verification timestamps so you know when data went stale.
For large lists, validate syntax first. Then verify deliverability. You avoid spending verification calls on rows that fail basic schema or import rules.
Internal admin tools
For internal tools, optimize for clarity and traceability.
Recommended rules:
- Use the same backend schema as public APIs.
- Show exact validation errors.
- Require confirmation before overriding risky or undeliverable results.
- Log manual overrides.
- Store the previous and new email values.
- Re-verify when an admin changes an email address.
Admins need enough context to make safe exceptions. Give them verdicts, reasons, timestamps, and audit logs.
JSON Schema gives you the first reliable gate: the payload is shaped correctly, and the email field looks like an email address. Real verification gives you the second gate: the address is likely safe to send to. Use both, in that order.


