Article content and detailed guides remain in English. The selected language applies to controls and quick instructions.

Back to articles

Email Validation API Integration: A Developer's Guide

On this page

Why Use a Validation API

Email validation APIs let you programmatically check whether an email address is valid before accepting it into your system or sending to it. Instead of manually uploading CSV files to a verification service, you integrate the check directly into your application.

Common integration points:

  • Signup forms (validate before creating an account).
  • Contact import flows (validate during bulk import).
  • CRM data entry (validate when a sales rep adds a contact).
  • Data pipelines (validate as part of an automated processing workflow).
  • Checkout pages (validate before processing an order).

Choosing an API

Key evaluation criteria

Accuracy. The percentage of addresses correctly classified as valid, invalid or risky. Test each provider against a known list of valid and invalid addresses.

Speed. Response time per check. For real-time form validation, you need under 2 seconds. For batch processing, throughput (checks per second) matters more.

Checks performed. What does the API actually verify?

Check What it does Speed
Syntax Validates email format Instant
DNS/MX Verifies domain has mail servers Fast (ms)
Disposable detection Flags temporary email services Instant
Role-based detection Flags shared inboxes (info@, admin@) Instant
SMTP verification Connects to server, checks if mailbox exists 1-5 seconds
Catch-all detection Identifies domains that accept all addresses 1-5 seconds
Spam trap detection Checks against known spam trap databases Varies
Free provider detection Flags Gmail, Yahoo, Outlook, etc. Instant

Rate limits. How many requests per second or minute does the API allow? This determines whether it can handle your form traffic or batch processing needs.

Pricing. Most providers charge per verification. Compare cost at your expected volume.

Uptime and reliability. For real-time form validation, the API is in the critical path of user signups. Check the provider's SLA and status page history.

Providers with APIs

Provider Single check Bulk API Webhook Starting price
ZeroBounce Yes Yes Yes ~$0.008/check
NeverBounce Yes Yes Yes ~$0.008/check
Emailable Yes Yes Yes ~$0.007/check
BriteVerify Yes Yes No ~$0.01/check
Bouncer Yes Yes Yes ~$0.008/check
MillionVerifier Yes Yes No ~$0.003/check
Kickbox Yes Yes Yes ~$0.01/check

Pricing varies by volume. Most providers offer lower per-check rates at higher volumes.

Single-Check Integration

Request format

Most APIs accept a simple GET or POST request:

GET https://api.verificationservice.example.com/v1/verify?email=user@example.com
Authorization: Bearer YOUR_API_KEY

Or:

POST https://api.verificationservice.example.com/v1/verify
Content-Type: application/json
Authorization: Bearer YOUR_API_KEY

{
  "email": "user@example.com"
}

Response format

A typical response:

{
  "email": "user@example.com",
  "result": "valid",
  "reason": "mailbox_exists",
  "disposable": false,
  "role": false,
  "free": false,
  "catch_all": false,
  "mx_found": true,
  "smtp_check": true,
  "score": 95,
  "did_you_mean": null
}

Result categories

Result Meaning Action
valid Mailbox exists and accepts mail Accept
invalid Mailbox does not exist or domain has no MX Reject
catch_all Domain accepts all addresses (cannot confirm individual mailbox) Accept with caution
disposable Temporary email service Reject (for signups) or accept (for content downloads)
role Shared inbox (info@, admin@) Accept but flag
unknown Could not determine (timeout, greylisting) Accept and recheck later

Python implementation

import requests
import time

API_KEY = "your_api_key"
API_URL = "https://api.verificationservice.example.com/v1/verify"

def verify_email(email, timeout=5, retries=2):
    """Verify a single email address."""
    for attempt in range(retries):
        try:
            response = requests.get(
                API_URL,
                params={"email": email},
                headers={"Authorization": f"Bearer {API_KEY}"},
                timeout=timeout
            )
            response.raise_for_status()
            data = response.json()

            return {
                "email": email,
                "valid": data["result"] == "valid",
                "result": data["result"],
                "disposable": data.get("disposable", False),
                "role": data.get("role", False),
                "catch_all": data.get("catch_all", False),
            }

        except requests.exceptions.Timeout:
            if attempt < retries - 1:
                time.sleep(1)
                continue
            # Fail open: accept the address and verify later
            return {
                "email": email,
                "valid": True,
                "result": "timeout",
                "disposable": False,
                "role": False,
                "catch_all": False,
            }

        except requests.exceptions.RequestException as e:
            if attempt < retries - 1:
                time.sleep(1)
                continue
            return {
                "email": email,
                "valid": True,  # Fail open
                "result": "error",
                "error": str(e),
            }

JavaScript implementation (Node.js)

const axios = require('axios');

const API_KEY = 'your_api_key';
const API_URL = 'https://api.verificationservice.example.com/v1/verify';

async function verifyEmail(email, timeout = 5000) {
  try {
    const response = await axios.get(API_URL, {
      params: { email },
      headers: { Authorization: `Bearer ${API_KEY}` },
      timeout,
    });

    const data = response.data;
    return {
      email,
      valid: data.result === 'valid',
      result: data.result,
      disposable: data.disposable || false,
      role: data.role || false,
      catchAll: data.catch_all || false,
    };
  } catch (error) {
    // Fail open
    return {
      email,
      valid: true,
      result: 'error',
      error: error.message,
    };
  }
}

Bulk/Batch Integration

When to use batch

  • Verifying existing lists (CRM cleanup, pre-campaign verification).
  • Processing extracted email lists (after extraction with Email Extractor).
  • Nightly or scheduled verification of new contacts.

Workflow

  1. Submit a list of addresses to the batch endpoint.
  2. Receive a batch ID.
  3. Poll for completion or receive a webhook when done.
  4. Download results.

Batch submission

def submit_batch(emails):
    """Submit a list of emails for batch verification."""
    response = requests.post(
        f"{API_URL}/batch",
        json={"emails": emails},
        headers={"Authorization": f"Bearer {API_KEY}"},
        timeout=30
    )
    response.raise_for_status()
    return response.json()["batch_id"]

Polling for results

def check_batch(batch_id, max_attempts=60, interval=10):
    """Poll for batch completion."""
    for _ in range(max_attempts):
        response = requests.get(
            f"{API_URL}/batch/{batch_id}",
            headers={"Authorization": f"Bearer {API_KEY}"},
            timeout=10
        )
        data = response.json()

        if data["status"] == "completed":
            return data["results"]
        elif data["status"] == "failed":
            raise Exception(f"Batch failed: {data.get('error')}")

        time.sleep(interval)

    raise Exception("Batch verification timed out")

Webhook processing

Instead of polling, configure a webhook URL that the API calls when the batch is done:

from flask import Flask, request

app = Flask(__name__)

@app.route('/webhook/verification', methods=['POST'])
def verification_webhook():
    data = request.json
    batch_id = data['batch_id']
    results = data['results']

    # Process results
    valid = [r for r in results if r['result'] == 'valid']
    invalid = [r for r in results if r['result'] == 'invalid']

    # Update your database
    # ...

    return {'status': 'received'}, 200

Best Practices

Fail open for real-time checks

If the validation API is down or slow, accept the email address and verify it later in batch. Blocking form submissions because a third-party API is unavailable loses you real leads.

Cache results

Cache verification results for a reasonable period (24-72 hours). If the same address is submitted again, use the cached result instead of making another API call.

from functools import lru_cache
from datetime import datetime, timedelta

# Simple in-memory cache
verification_cache = {}

def verify_with_cache(email, cache_hours=24):
    email_lower = email.lower()
    cached = verification_cache.get(email_lower)

    if cached and cached['expires'] > datetime.now():
        return cached['result']

    result = verify_email(email)
    verification_cache[email_lower] = {
        'result': result,
        'expires': datetime.now() + timedelta(hours=cache_hours)
    }
    return result

Rate limiting

Respect the API's rate limits. Implement exponential backoff on 429 (Too Many Requests) responses:

def verify_with_backoff(email, max_retries=3):
    for attempt in range(max_retries):
        result = verify_email(email)

        if result.get('result') != 'rate_limited':
            return result

        wait = 2 ** attempt  # 1, 2, 4 seconds
        time.sleep(wait)

    return {'email': email, 'valid': True, 'result': 'rate_limited'}

Handle all result types

Do not just check for "valid" and "invalid." Handle every result type the API can return:

def should_accept(result):
    """Decide whether to accept an email based on verification result."""
    status = result['result']

    if status == 'valid':
        return True
    elif status == 'invalid':
        return False
    elif status == 'catch_all':
        return True  # Accept but flag for monitoring
    elif status == 'disposable':
        return False  # Or True, depending on use case
    elif status == 'role':
        return True  # Accept but exclude from cold outreach
    elif status == 'unknown':
        return True  # Accept and recheck later
    elif status in ('timeout', 'error'):
        return True  # Fail open
    else:
        return True  # Unknown status, fail open

Log everything

Log every verification request and result. This data helps you:

  • Track API costs.
  • Identify patterns in invalid addresses (bad data sources).
  • Debug issues when addresses that were verified as valid still bounce.

Separate validation from business logic

Keep your validation function separate from the decision about what to do with the result. One application might reject disposable addresses (signup form), while another accepts them (content download).

Integration with Email Extractor

When processing extracted email lists:

  1. Extract and deduplicate emails from your source files using Email Extractor.
  2. Download the CSV results.
  3. Feed the CSV into your batch verification pipeline.
  4. Process the verification results.
  5. Import only valid addresses into your CRM or email platform.

This creates an automated pipeline from raw data to a verified, ready-to-use email list.

Extract emails

Explore tools

Verify emails

Check address validity before using your list.

ZeroBounce

Email Verification

Verifies email lists and provides tools for monitoring deliverability.

Useful when list cleaning and sender health belong in one workflow.

Explore ZeroBounce (opens in a new tab)