# Python

Detect disposable emails in Python with synchronous or asynchronous IronDome clients. Includes connection reuse and API error handling.

Check addresses in your Python backend before creating accounts. Keep the API key in server configuration and reuse a client so HTTP connections stay pooled.

## Availability

PyPI publication is pending. Install version 0.2.0 from the [public tagged source](https://github.com/IrondomeDev/sdks/tree/javascript/v0.2.0/python); this requires Git:

```sh
python -m pip install "git+https://github.com/IrondomeDev/sdks.git@javascript/v0.2.0#subdirectory=python"
```

Python 3.11 or newer is required.

## Synchronous client

Set `IRONDOME_API_KEY` in your server environment. `Client` defaults to `https://api.irondome.dev`.

```python
import os
from irondome import APIError, Client

client = Client(os.environ["IRONDOME_API_KEY"])

def check_email(email: str):
    try:
        return client.check(email)
    except APIError as error:
        print(error.status_code, error.code, error.request_id)
        raise

with client:
    print(check_email("person@example.com"))
```

The synchronous client can be shared across threads. Create it after a process fork and close it only when the worker is shutting down. Do not create a client for each address.

## Async client

Use `AsyncClient` within one long-lived event loop. In an ASGI application, create it during application startup and close it during shutdown.

```python
import asyncio
import os
from irondome import AsyncClient

async def main():
    async with AsyncClient(os.environ["IRONDOME_API_KEY"]) as client:
        result = await client.check("person@example.com")
        print(result)

asyncio.run(main())
```

This standalone example uses one event loop and one client. In an ASGI server, retain the `AsyncClient` across requests and close it during shutdown. Do not share an async client across event loops or repeated `asyncio.run` calls.

## Results and failures

`check()` returns `provider`, `valid`, `disposable`, and `reason`, with optional `request_id` and `detector_version`. `valid` does not verify mailbox existence or deliverability. `APIError` exposes `status_code`, `code`, `request_id`, and `retry_after_seconds`. Local validation, transport, timeout, busy, and closed-client errors are separate failures. Handle them separately from classifications.

`client.warmup()` sends an unauthenticated health request on the same pool. It is optional and does not verify the API key. Use it ahead of independent work if useful, not as a required step before every check.

The SDK also provides `check_bulk(emails)` for up to 100 addresses. Each syntactically valid address counts as one check. See the [bulk API guide](/docs/api/bulk) and [performance guide](/docs/guides/performance).
