Metadata-Version: 2.4
Name: isitdisposable
Version: 0.1.1
Summary: Detect disposable, temporary, and throwaway email addresses in real time with a simple Python client for the isitdisposable.com API.
Project-URL: Homepage, https://isitdisposable.com
Project-URL: Repository, https://github.com/richelo/isitdisposable-python
Project-URL: Documentation, https://isitdisposable.com/docs
Author: Richelo Killian
License-Expression: MIT
License-File: LICENSE
Keywords: MX check,burner email,disposable email,email validation,email verification,temporary email
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Communications :: Email
Classifier: Topic :: Internet
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.10
Requires-Dist: httpx>=0.24
Description-Content-Type: text/markdown

# isitdisposable

Detect disposable, temporary, and burner email addresses in real time from Python, using the [isitdisposable.com](https://isitdisposable.com) Application Programming Interface (API).

## Install

```bash
pip install isitdisposable
```

or with [uv](https://docs.astral.sh/uv/):

```bash
uv add isitdisposable
```

You will need an API key from [isitdisposable.com](https://isitdisposable.com). A free tier is available, so you can try this out without a credit card.

## Quick start: check an email address

```python
from isitdisposable import Client

client = Client(api_key="isid_live_your_key_here")

result = client.check(email="someone@example.com")

if result.disposable:
    print("This looks like a disposable email address.")
else:
    print("This looks like a real, ongoing email address.")
```

`api_key` can also come from the `ISITDISPOSABLE_API_KEY` environment variable, so in most setups you can just write `Client()`.

## Example: block disposable signups in a Django form

```python
# forms.py
from django import forms
from isitdisposable import Client

client = Client()  # reads ISITDISPOSABLE_API_KEY from the environment


class SignupForm(forms.Form):
    email = forms.EmailField()

    def clean_email(self):
        email = self.cleaned_data["email"]
        result = client.check(email=email)

        if result.disposable:
            raise forms.ValidationError(
                "Please sign up with an email address you check regularly. "
                "Disposable or throwaway addresses are not allowed."
            )

        return email
```

## Example: block disposable signups in a FastAPI dependency

```python
# dependencies.py
from fastapi import Depends, HTTPException
from isitdisposable import AsyncClient

async_client = AsyncClient()  # reads ISITDISPOSABLE_API_KEY from the environment


async def reject_disposable_email(email: str) -> str:
    result = await async_client.check(email=email)

    if result.disposable:
        raise HTTPException(
            status_code=400,
            detail="Please use an email address you check regularly, not a disposable one.",
        )

    return email


# In a route:
# @app.post("/signup")
# async def signup(email: str = Depends(reject_disposable_email)):
#     ...
```

## Checking a batch

Check up to 100 emails or domains in a single request. Items can be plain strings (anything containing an "@" is treated as an email, everything else as a domain) or dicts:

```python
result = client.check_batch(
    [
        "someone@example.com",
        "example.org",
        {"domain": "another-example.com"},
    ]
)

for item in result.results:
    print(item.domain, item.disposable, item.action)

print(f"Checked {result.count} items.")
```

## Fail open by design

Signup forms and checkout flows should never break because of an email checking service having a bad moment. This client fails open by default: if the isitdisposable.com service cannot be reached, times out, is rate limiting you, or has an internal error, `check()` and `check_batch()` do not raise. Instead they return a result where `checked` is `False`, `disposable` is `None`, and `action` is `"allow"`, and a warning is logged through the standard `logging` module under the logger name `"isitdisposable"`. Your form keeps working; you can watch the warning logs to notice if this starts happening a lot.

If you would rather see failures as exceptions (for example in a background job where you want to retry later), turn this off:

```python
client = Client(fail_open=False)
```

With `fail_open=False`, a connection problem raises `NetworkError`, a rate limit response raises `RateLimitError`, and a server error raises `ServerError`. Invalid requests (a missing or malformed API key, or a request that is missing both an email and a domain) always raise, in either mode, because those indicate something in your own code needs fixing rather than a temporary service problem.

## Response fields

Every check returns a result with these fields. Any field can be `None` if the underlying signal was not evaluated for that request.

| Field | Type | Meaning |
| --- | --- | --- |
| `checked` | `bool` | Whether a real check was performed (`False` on a fail-open response). |
| `normalized_email` | `str` or `None` | The email address you sent, normalized. |
| `domain` | `str` or `None` | The domain that was evaluated. |
| `disposable` | `bool` or `None` | The core verdict: whether the domain is a disposable or throwaway email provider. |
| `mx_valid` | `bool` or `None` | Whether the domain has a working mail server. |
| `role_account` | `bool` or `None` | Whether the local part looks like a role address (for example `support@`). |
| `relay` | `bool` or `None` | Whether the domain is a mail relay or forwarding service. |
| `public_domain` | `bool` or `None` | Whether the domain is a large public provider (for example a well known free email service). |
| `spam_risk` | `bool` or `None` | Whether the domain appears on a spam or abuse reputation list. Only populated if your account has this signal enabled. |
| `mx_masked` | `bool` or `None` | Whether the domain's mail server is masked or hidden behind a routing service. |
| `did_you_mean` | `str` or `None` | A suggested correction if the domain looks like a likely typo. |
| `mx_records` | `list[str]` or `None` | The mail server records found for the domain. |
| `action` | `str` | The recommended action for your account's policy: `"allow"`, `"warn"`, or `"block"`. |
| `reason` | `str` or `None` | A machine readable reason code. This set is open ended; treat unknown values as informational. |
| `raw` | `dict` | The full parsed response, including any fields not yet listed above, for forward compatibility. |

## Links

- Website: [https://isitdisposable.com](https://isitdisposable.com)
- Documentation: [https://isitdisposable.com/docs](https://isitdisposable.com/docs)
- A free tier is available, so you can get started without a credit card.
