Skip to main content

Official Python client for the BounceZero email verification API

Project description

BounceZero — Python

Real-time & bulk email verification with a 5-stage intelligence pipeline

PyPI version Python versions License: MIT Docs Status

Documentation · Dashboard · API Status · Support


The official Python client for the BounceZero email verification API. A single file, zero dependencies (standard library only), and a small, predictable surface designed for production workloads — from a signup form that validates one address in real time to a nightly job that cleans millions.

from bouncezero import BounceZero

client = BounceZero("bz_live_...")
result = client.verify("someone@example.com")

print(result["classification"], result["score"])   # → verified 98

Why BounceZero

Every address is scored across 40+ signals through a five-stage pipeline — syntax, DNS/MX, SMTP mailbox probing, disposable & role detection, and a Bayesian + ML confidence model — so you catch invalid, risky, and low-value addresses before they cost you deliverability.

  • Real-time single verification in ~500 ms–2 s, or async bulk for large lists
  • 🎯 Six clear verdicts (verified / invalid / catch_all / disposable / risky / unknown) plus threat flags
  • 🔁 Idempotent bulk submits — a network retry can never double-charge you
  • 🧪 Sandbox keys to build & test without spending credits
  • 🔒 Signed webhooks with a one-line verifier
  • 📦 Zero dependencies, typed errors, automatic retries with backoff

Installation

pip install bouncezero

Requires Python 3.8+. No transitive dependencies.

Authentication

Grab your API key from the dashboard and pass it to the client. Keep live keys server-side — never ship them in client code.

from bouncezero import BounceZero

client = BounceZero("bz_live_...")

Quick start

# 1 — Verify a single address
result = client.verify("jane@example.com")
if result["classification"] == "verified":
    add_to_mailing_list(result["email"])

# 2 — Batch up to 100 synchronously
report = client.verify_batch(["a@example.com", "b@example.com"])
print(report["summary"])           # {'verified': 1, 'invalid': 1, ...}

# 3 — Async bulk for large lists (idempotency-safe)
job   = client.verify_bulk(emails, idempotency_key="import-2026-07-11")
final = client.wait_for_bulk(job["job_id"])
csv   = client.bulk_download(job["job_id"])

Verification result

verify() returns a dict with the full signal breakdown. The fields you'll use most:

Field Type Description
email str The address that was checked
classification str One of the six verdicts below
score int Confidence 0–100
is_deliverable bool | None True/False, or None when inconclusive
risk_level str low · medium · high
recommendation str Human-readable guidance

Classifications

Verdict Meaning Safe to send?
verified Mailbox exists and accepts mail
invalid Mailbox does not exist — will hard bounce
catch_all Domain accepts everything; mailbox unconfirmable ⚠️
disposable Temporary/throwaway provider ⚠️
risky Concrete negative signals (full mailbox, poor reputation…) ⚠️
unknown Mail server blocked/greylisted the probe — retry later

Two rare threat verdicts — complainer and spamtrap — may also appear; remove those addresses immediately (details in threat_type).

API reference

Method Description
verify(email, depth="standard") Verify one address. depth: standard · deep · ultra
verify_batch(emails) Verify up to 100 addresses synchronously
verify_bulk(emails, idempotency_key=None) Submit an async bulk job
bulk_status(job_id) Poll job progress
bulk_results(job_id, limit=1000, offset=0) Paginated results
bulk_download(job_id) Download completed results as CSV bytes
wait_for_bulk(job_id, poll_interval=5.0, timeout=3600.0) Block until a job finishes
domain(domain) Domain-level intelligence (MX, provider, catch-all…)
analyze_list(emails) Free list-quality analysis — no verification, no credits
BounceZero.verify_webhook_signature(body, header, secret) Validate a webhook signature

Bulk verification

Bulk jobs run asynchronously. Submit, then either poll or wait:

job = client.verify_bulk(emails, idempotency_key="crm-sync-42")

# Option A — block until done
final = client.wait_for_bulk(job["job_id"], poll_interval=10)

# Option B — poll yourself
status = client.bulk_status(job["job_id"])
print(status["completed"], "/", status["total"])

# Fetch results (paginated) or download the full CSV
page = client.bulk_results(job["job_id"], limit=1000, offset=0)
csv  = client.bulk_download(job["job_id"])

Idempotency — pass an idempotency_key (any unique string). Replaying the same key returns the original job instead of creating and charging for a duplicate, so retries after a timeout are always safe.

Error handling

Every failure raises a subclass of BounceZeroError, each carrying .status_code and .payload:

from bouncezero import (
    BounceZero, AuthenticationError, InsufficientCreditsError,
    RateLimitError, NotFoundError, BounceZeroError,
)

try:
    result = client.verify("someone@example.com")
except InsufficientCreditsError:
    top_up_credits()
except RateLimitError as e:
    time.sleep(e.retry_after or 60)
except AuthenticationError:
    alert("Check your API key")
except BounceZeroError as e:
    log.error("BounceZero %s: %s", e.status_code, e)
Exception HTTP When
AuthenticationError 401 / 403 Missing, invalid, disabled, or IP-restricted key
InsufficientCreditsError 402 Not enough credits
NotFoundError 404 Unknown job or resource
RateLimitError 429 Plan rate limit exceeded (see .retry_after)
BounceZeroError other Any other API/transport error

Requests automatically retry on 429 and 5xx with exponential backoff (honoring Retry-After); tune with max_retries.

Rate limits

Limits are per API key, per minute, by plan. Responses include X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset.

Plan Requests / min
Free 30
Starter · Growth 100
Professional · Business · Scale 300
Ultimate · Enterprise 1000

Sandbox / testing

Create a sandbox key (bz_test_ prefix) in the dashboard. It returns deterministic mock results, never spends credits, and never performs a real probe — the local part of the address picks the verdict:

sandbox = BounceZero("bz_test_...")
sandbox.verify("verified@example.com")["classification"]    # → "verified"
sandbox.verify("risky@example.com")["classification"]       # → "risky"

Supported on verify(). See the sandbox docs.

Webhooks

BounceZero signs every webhook with X-BounceZero-Signature (HMAC-SHA256). Always verify against the raw request body before parsing:

from bouncezero import BounceZero

@app.post("/webhooks/bouncezero")
def handle(request):
    if not BounceZero.verify_webhook_signature(
        request.raw_body,
        request.headers.get("X-BounceZero-Signature", ""),
        signing_secret,        # from Dashboard → Webhooks
    ):
        return 400
    event = request.json()
    ...

Configuration

client = BounceZero(
    api_key="bz_live_...",
    base_url="https://app.bouncezero.io",  # override for a dedicated region
    timeout=60,                            # seconds
    max_retries=2,                         # retries on 429 / 5xx
)

Support

License

MIT © BounceZero Ltd

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

bouncezero-0.1.0.tar.gz (7.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

bouncezero-0.1.0-py3-none-any.whl (8.4 kB view details)

Uploaded Python 3

File details

Details for the file bouncezero-0.1.0.tar.gz.

File metadata

  • Download URL: bouncezero-0.1.0.tar.gz
  • Upload date:
  • Size: 7.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for bouncezero-0.1.0.tar.gz
Algorithm Hash digest
SHA256 07d376d590673f89473cc4ee2156ebbb45d4c02ccd0fbda3334d3bf578cb23e8
MD5 c5a69e3f2e8d5f0fa16c8ddf929948a4
BLAKE2b-256 c88e1e3832af8104f92bdc1ca8f39b9fcd222b6d9040825213da9646ad64d14c

See more details on using hashes here.

Provenance

The following attestation bundles were made for bouncezero-0.1.0.tar.gz:

Publisher: publish.yml on BounceZero/bouncezero-python

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file bouncezero-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: bouncezero-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 8.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for bouncezero-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 7997c3c1e21d5b524c035bc52fc42c3069f510323fcaeb76c638c92882ceb0ce
MD5 5a6164726cbda6fdc28469b8fb088c11
BLAKE2b-256 d7c9d56e11a48dd5a350c21bdaf9e84c8cdf02f9c4b23beff410aa0871dbe458

See more details on using hashes here.

Provenance

The following attestation bundles were made for bouncezero-0.1.0-py3-none-any.whl:

Publisher: publish.yml on BounceZero/bouncezero-python

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page