Email Verification API Python 2026 - Integration Guide with Code Examples | BounceZero
BlogDeveloper Guides

Email Verification API Python 2026
Integration Guide with Code Examples

This guide covers how to integrate BounceZero’s email verification API in Python - from a simple synchronous requests call to async batch verification with httpx, Flask/Django integration patterns, and error handling for production use.

By BounceZero Team |July 2026 |8 min read

1. Basic Synchronous Verification (requests)

pip install requests
import requests

API_KEY = "YOUR_BOUNCEZERO_API_KEY"
BASE_URL = "https://api.bouncezero.io/v1"

def verify_email(email: str) -> dict:
    """Verify a single email address and return the full result."""
    response = requests.post(
        f"{BASE_URL}/verify",
        json={"email": email},
        headers={"Authorization": f"Bearer {API_KEY}"},
        timeout=10
    )
    response.raise_for_status()
    return response.json()

def is_safe_to_send(email: str) -> bool:
    """Return True only if the email is valid and non-disposable."""
    result = verify_email(email)
    if result["result"] == "invalid":
        return False
    if result.get("is_disposable"):
        return False
    # Accept valid and high-confidence catch-all
    if result["result"] == "catch-all" and result.get("score", 0) < 70:
        return False
    return True

# Usage
if is_safe_to_send("[email protected]"):
    print("Safe to send")
else:
    print("Suppress this email")

The result field returns: valid, invalid, catch-all, disposable, or unknown. The score field (0-100) rates catch-all confidence - 70+ is safe to send.

2. Async Batch Verification (httpx + asyncio)

pip install httpx
import asyncio
import httpx

API_KEY = "YOUR_BOUNCEZERO_API_KEY"
BASE_URL = "https://api.bouncezero.io/v1"
CONCURRENCY = 10  # max concurrent requests (respect rate limits)

async def verify_email_async(client: httpx.AsyncClient, email: str) -> dict:
    response = await client.post(
        f"{BASE_URL}/verify",
        json={"email": email},
        headers={"Authorization": f"Bearer {API_KEY}"},
    )
    response.raise_for_status()
    data = response.json()
    return {"email": email, **data}

async def verify_batch(emails: list[str]) -> list[dict]:
    sem = asyncio.Semaphore(CONCURRENCY)

    async def bounded_verify(client, email):
        async with sem:
            try:
                return await verify_email_async(client, email)
            except Exception as e:
                return {"email": email, "result": "error", "error": str(e)}

    async with httpx.AsyncClient(timeout=15) as client:
        tasks = [bounded_verify(client, email) for email in emails]
        return await asyncio.gather(*tasks)

# Usage
emails = ["[email protected]", "[email protected]", "[email protected]"]
results = asyncio.run(verify_batch(emails))

for r in results:
    status = r.get("result", "error")
    print(f"{r['email']}: {status}")

The semaphore limits concurrency to 10 requests at a time. For lists over 500 emails, the bulk upload endpoint (section 3) is faster and more efficient.

3. CSV Batch Verification

import csv
import asyncio
import httpx

API_KEY = "YOUR_BOUNCEZERO_API_KEY"

async def verify_csv(input_path: str, output_path: str):
    # Read emails from CSV
    emails = []
    with open(input_path, newline="") as f:
        reader = csv.DictReader(f)
        fieldnames = reader.fieldnames or []
        rows = list(reader)
        for row in rows:
            emails.append(row.get("email", ""))

    # Verify all emails
    from verify_email_async import verify_batch  # import from section 2
    results = await verify_batch(emails)
    result_map = {r["email"]: r for r in results}

    # Write enriched CSV
    out_fields = list(fieldnames) + ["bz_result", "bz_score", "bz_is_disposable"]
    with open(output_path, "w", newline="") as f:
        writer = csv.DictWriter(f, fieldnames=out_fields)
        writer.writeheader()
        for row in rows:
            email = row.get("email", "")
            res = result_map.get(email, {})
            row["bz_result"] = res.get("result", "")
            row["bz_score"] = res.get("score", "")
            row["bz_is_disposable"] = res.get("is_disposable", "")
            writer.writerow(row)

    print(f"Written {len(rows)} rows to {output_path}")

asyncio.run(verify_csv("leads.csv", "leads_verified.csv"))

This appends three columns to the existing CSV: bz_result, bz_score, and bz_is_disposable. Filter rows where bz_result == "invalid" before loading to your sequencer.

4. Django / Flask Integration Pattern

Flask - validate at signup
from flask import Flask, request, jsonify
import requests, os

app = Flask(__name__)
API_KEY = os.environ["BOUNCEZERO_API_KEY"]

@app.route("/register", methods=["POST"])
def register():
    email = request.json.get("email", "").strip()

    # Verify email before creating account
    try:
        res = requests.post(
            "https://api.bouncezero.io/v1/verify",
            json={"email": email},
            headers={"Authorization": f"Bearer {API_KEY}"},
            timeout=5
        ).json()
    except Exception:
        # Fail open: allow registration if API is unavailable
        res = {}

    if res.get("result") == "invalid":
        return jsonify({"error": "Invalid email address."}), 422
    if res.get("is_disposable"):
        return jsonify({"error": "Disposable emails are not allowed."}), 422

    # Create user account...
    return jsonify({"status": "ok"}), 201

Note the fail open pattern: if the API call fails (timeout, network error), registration proceeds. This prevents the verification API from becoming a hard dependency that breaks signup. Log failures for monitoring.

API Response Fields

Field Type Description
result string Classification: valid | invalid | catch-all | disposable | unknown
score int 0-100 Confidence score - especially useful for catch-all decisions
is_disposable boolean True if the domain is a known disposable email provider
is_role boolean True if the local part is role-based (info, admin, sales, etc.)
mx_found boolean True if the domain has valid MX records
smtp_valid boolean True if the SMTP RCPT TO response was positive

New to verification? Start with the complete email verification guide.

Frequently Asked Questions

How do I verify email addresses in Python?

Use the BounceZero API with Python’s requests library: response = requests.post(‘https://api.bouncezero.io/v1/verify’, json={‘email’: email}, headers={‘Authorization’: ‘Bearer YOUR_KEY’}). The result contains ‘result’ (valid/invalid/catch-all/disposable/unknown), ‘is_disposable’, ‘is_role’, and ‘score’ fields. For async code, use httpx.AsyncClient.

How do I verify emails in bulk with Python?

For lists under 500 emails, use asyncio + httpx with a semaphore (CONCURRENCY = 10) to make concurrent API calls. For 1,000+ emails, use the bulk upload API endpoint - upload CSV, poll for completion, download enriched results.

What Python libraries do I need for email verification?

For synchronous verification: requests (pip install requests). For async: httpx (pip install httpx) and asyncio (standard library). For CSV handling: pandas or the built-in csv module. No other dependencies needed for BounceZero API integration.

Get your API key. Start verifying in minutes.

100 free credits on every account. No credit card required. Full API docs available after signup.

AL

Written by

Ayoub Lebda

Founder, BounceZero - Email-infrastructure engineer

Ayoub built BounceZero's 5-stage validation pipeline, its dedicated BGP-announced IP infrastructure, and the Patroni HA PostgreSQL cluster behind every verification. Previously built high-volume email delivery infrastructure. Trained at 1337 Benguerir (École 42 network, 2019). Open-source: bgp_analyzer.

Build with the BounceZero API

Endpoints, code samples, and language guides