Skip to main content

isitdisposable

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

Install

pip install isitdisposable

or with uv:

uv add isitdisposable

You will need an API key from isitdisposable.com. A free tier is available, so you can try this out without a credit card.

Quick start: check an email address

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

# 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

# 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:

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:

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

Release files for isitdisposable 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for isitdisposable 0.1.1
File Size Uploaded
isitdisposable-0.1.1.tar.gz 26.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for isitdisposable 0.1.1
File Interpreter ABI Platform
isitdisposable-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size:40.9 kB

Release files / isitdisposable-0.1.1.tar.gz

Download URL isitdisposable-0.1.1.tar.gz
Size 26.4 kB
Tags Source
SHA-256 checksum
How to use checksums
24d334c846a6a6aeb03ef0354dbe5288e2e50028be409033ee4e664137690866
BLAKE2b-256 checksum
How to use checksums
c9510b8708d28770a93dd9640c05af1dab32b30c80f770c45d10f87d93563673
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.19 {"installer":{"name":"uv","version":"0.11.19","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"13","id":"trixie","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / isitdisposable-0.1.1-py3-none-any.whl

Download URL isitdisposable-0.1.1-py3-none-any.whl
Size 14.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
df6c31570fc5906424b1c1be46be0609150b3af65f37b07aee33bcae3be742f9
BLAKE2b-256 checksum
How to use checksums
0762f7e149c46b205f13adea1f4a26e65432b5bd91fb284094933ea7eb86f00d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.19 {"installer":{"name":"uv","version":"0.11.19","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"13","id":"trixie","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page