Spaw Python SDK: verify emails from Python

updated · September 3, 2026

The official spaw-sdk package wraps every Spaw endpoint with typed results and one exception class per API code. Standard library only, Python 3.9 or newer.

Mechanism
Official client, standard library only
Status
Built, awaiting publication on PyPI as spaw-sdk
Auth
Secret API key passed to the client
Cost
1 credit per answered lookup, undeliverable answers free
Requires
Python 3.9 or newer

The Python client is a thin wrapper over the REST API: one method per endpoint, the API's data and meta blocks returned exactly as documented, and a typed exception for every error code. It has no dependencies beyond the standard library, ships type hints, and works on Python 3.9 and newer.

The package is built and will be published on PyPI as spaw-sdk; the distribution name differs from the import name because spaw was already taken. Until the listing is live, the plain REST calls in the API reference do the same job with a few more lines.

Install and verify one address

  1. Create a secret key on the API keys page.
  2. Install the package once it is published:
pip install spaw-sdk
  1. Verify an address. The import name is spaw:
from spaw import Client

client = Client("sk_live_…")

result = client.verify_email("[email protected]")
print(result.data["deliverable"])   # "deliverable", "risky" or "undeliverable"
print(result.data["reason"])        # e.g. "catch_all", or None when deliverable
print(result.data["risk_score"])    # 0–100, a sum of published weights
print(result.meta["credits_used"])  # 1 for a fresh answered lookup, 0 otherwise

Every reason and smtp_reason value is explained on the verdict reasons pages, and result.data carries all 27 documented fields, including did_you_mean, mx_provider and smtp_checked_at.

Everything the client does

Method Endpoint
verify_email(email, callback_url=None, callback_secret=None) POST /email
verify_emails(emails) POST /email/batch, up to 50
domain(domain) GET /email/domain/{domain}
create_bulk_job(emails, webhook_url=None), get_bulk_job(id), cancel_bulk_job(id), download_bulk_results(id, variant=None) the bulk endpoints, up to 100,000 addresses
list_suppressions(page=1), add_suppressions(emails), remove_suppression(id) the suppression list
report_feedback(items), feedback_summary() delivery outcomes and measured accuracy
account() the live credit balance
validate_phone(phone, country=None), lookup_ip(ip) the phone and IP endpoints

A batch keeps the API's shape: data["results"] holds one {data, meta} per address in input order, and meta["stopped_reason"] is set instead of an exception when the balance runs out part-way, so paid results are never lost.

Handle errors

Every failure raises a subclass of SpawError carrying code, message, http_status and request_id; no credits are spent on a failed request.

from spaw import InsufficientCreditsError, RateLimitedError, SpawError

try:
    result = client.verify_email("[email protected]")
except InsufficientCreditsError:
    ...  # nothing ran and nothing was billed
except RateLimitedError as error:
    ...  # error.retry_after seconds, from the Retry-After header
except SpawError as error:
    print(error.code, error.http_status, error.request_id)

AuthenticationError maps UNAUTHENTICATED, ValidationError maps VALIDATION_FAILED with errors keyed by field, NotFoundError covers a bulk job or suppression entry that is not on the account, and SpawConnectionError means the API could not be reached. Pass max_retries=2 to the client to retry 429 and 5xx answers automatically, honouring Retry-After.

What to do with the verdict

Branch on deliverable. Keep deliverable addresses, drop undeliverable ones, and route risky ones by reason: disposable and likely_typo are usually refused, role depends on your use case, and catch_all is often a fine address whose mailbox simply cannot be confirmed, in which case mailbox_confidence gives you a number to threshold. Offer did_you_mean back to the user when it is set.

Cost

One credit per fresh deliverable or risky verdict. Undeliverable verdicts, invalid input, repeats within seven days and the spaw.test test addresses cost nothing, and every account gets 10 free lookups a month. Use [email protected] and its siblings in your test suite: they answer fixed results, cost nothing and never appear in your history.

Related

markdown version: /integrations/python-sdk.md

Verify addresses the same way

The Spaw API runs every check described here on each lookup, with an SMTP handshake that never sends mail. 10 free lookups a month, no card required.

Get your API key

More integrations