NewConnect Claude, Gemini, ChatGPT, and other AI agents to API Ninjas via our MCP server

How to Validate an Email Address in Python

Validate Email APIUpdated August 28, 2026
Create a free API key and it will be pre-filled into every code sample on this page. No credit card required.
A regex can tell you an email address looks right; it can't tell you the domain accepts mail or that the address isn't a throwaway. The Validate Email API checks all of that in one GET request. This guide covers the call, what each flag in the response means, and the two places validation earns its keep: sign-up forms and mailing-list cleanup.

Prerequisites

You need three things:

  • Python 3.8 or newer.
  • The requests library.
  • A free API Ninjas API key — issued instantly, no credit card. If you already have an account, it's on your profile page.
shell
pip install requests

Step 1: Validate your first address

The endpoint is /v1/validateemail and takes one parameter: email.

email_check.py
import requests response = requests.get( 'https://api.api-ninjas.com/v1/validateemail', params={'email': 'test@example.com'}, headers={'X-Api-Key': 'YOUR_API_KEY'}, timeout=10, ) response.raise_for_status() result = response.json() print('valid' if result['is_valid'] else 'invalid')

The request on the wire and the full response:

api.api-ninjas.com
GET/v1/validateemail?email=test@example.com
200 OKapplication/json
{ "email": "test@example.com", "is_valid": true, "is_disposable": false, "mx_found": true, "smtp_check": true }

Step 2: Read the four flags

Each flag answers a different question, from cheapest check to deepest:

FlagQuestion it answers
is_validIs the address syntactically well-formed (RFC 5322)?
mx_foundDoes the domain have mail servers (MX records) at all?
is_disposableIs the domain a known throwaway provider (mailinator, 10minutemail)?
smtp_checkDoes the domain's mail server respond to an SMTP probe?

No email is ever sent during validation — these are syntax, DNS, and server checks. That means a passing result guarantees the domain can receive mail, not that a particular inbox exists; it's the practical ceiling for any validator.

Step 3: Build a safe-to-send check

In practice you want one boolean, and it should combine three flags: well-formed, deliverable domain, not disposable. Here's the client with that helper — key in an environment variable, one shared session:

email_client.py
import os import requests API_URL = 'https://api.api-ninjas.com/v1/validateemail' session = requests.Session() session.headers['X-Api-Key'] = os.environ.get('API_NINJAS_KEY', 'YOUR_API_KEY') def validate_email(email: str) -> dict: response = session.get(API_URL, params={'email': email}, timeout=10) response.raise_for_status() return response.json() def is_safe_to_send(email: str) -> bool: """True only if the address is well-formed, deliverable, and not a throwaway.""" result = validate_email(email) return ( result['is_valid'] and result.get('mx_found', False) and not result.get('is_disposable', False) ) for email in ['user@gmail.com', 'fake@notarealdomain.xyz', 'user@mailinator.com']: print(f"{'OK ' if is_safe_to_send(email) else 'NO '} {email}")

Whether to also require smtp_check is a strictness dial: some legitimate mail servers decline probes, so requiring it trades a few false rejections for a cleaner list.

Step 4: Wire it into a sign-up form

The highest-value place for validation is registration, server-side, with a specific message per failure so users can actually fix their typo:

app.py
from flask import Flask, request, jsonify app = Flask(__name__) @app.route('/signup', methods=['POST']) def signup(): email = request.json.get('email', '') result = validate_email(email) if not result['is_valid']: return jsonify({'error': 'Please enter a valid email address'}), 400 if not result.get('mx_found'): return jsonify({'error': 'This email domain cannot receive mail'}), 400 if result.get('is_disposable'): return jsonify({'error': 'Disposable email addresses are not allowed'}), 400 # ...create the account... return jsonify({'ok': True})

Keep a simple regex on the client for instant feedback, but treat this server-side check as the real gate — anything running in the browser can be bypassed.

Step 5: Clean a whole list

For an existing mailing list, run every address through the same client and split the results. Bounced sends damage sender reputation, so this pays for itself before the next campaign:

clean_list.py
with open('emails.txt') as f: emails = [line.strip() for line in f if line.strip()] valid, invalid = [], [] for email in emails: result = validate_email(email) (valid if result['is_valid'] else invalid).append(email) print(f'Valid: {len(valid)}') print(f'Invalid: {len(invalid)}') with open('emails_clean.txt', 'w') as f: f.write('\n'.join(valid))

For lists beyond a few thousand, add a short time.sleep() between calls to stay inside your plan's rate limit. And when something does go wrong, handle it per-address so one failure doesn't stop the run:

errors.py
from requests.exceptions import HTTPError, RequestException try: result = validate_email('user@gmail.com') except HTTPError as error: status = error.response.status_code if status == 401: print('Missing or invalid API key') elif status == 429: print('Rate limit exceeded — throttle the loop') else: print(f'HTTP {status}: {error.response.text}') except RequestException as error: print(f'Network error: {error}')

Where to go from here

Contact hygiene rarely stops at email: the Validate Phone API does the same job for phone numbers, the Disposable Email Checker isolates the throwaway test, and the MX Lookup API exposes the raw DNS records. The complete script is below.

validate_emails.py

The complete script from this guide: safe-to-send logic, single addresses or a whole file from the command line.

Frequently asked questions

What checks does the API perform?

Syntax validation (RFC 5322), MX record lookup (the domain can receive mail), a disposable-provider check, and an SMTP-level probe. Each is reported as its own flag so you decide how strict to be.

Does the API send a test email?

No. Validation uses syntax checks, DNS lookups, and server probes — no email is sent. That means it verifies the domain can receive mail, not that a specific inbox exists.

How do I block disposable email addresses?

Check the is_disposable flag — it identifies known throwaway providers like mailinator and 10minutemail. Rejecting them at sign-up keeps trial abuse and bounce rates down.

Should I validate client-side or server-side?

Both, for different jobs: a simple regex client-side for instant feedback, and this API server-side as the real gate — client-side checks can be bypassed by anyone with DevTools.

Why validate at sign-up instead of just sending the email?

Bounces hurt your sender reputation, and fake sign-ups pollute your user data. Catching bad addresses before they enter the database is much cheaper than cleaning them out later.