Skip to main content

Detect disposable, temporary, and throwaway email addresses in real time with a simple Python client for the isitdisposable.com API.

Project description

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

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

isitdisposable-0.1.1.tar.gz (26.4 kB view details)

Uploaded Source

Built Distribution

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

isitdisposable-0.1.1-py3-none-any.whl (14.5 kB view details)

Uploaded Python 3

File details

Details for the file isitdisposable-0.1.1.tar.gz.

File metadata

  • Download URL: isitdisposable-0.1.1.tar.gz
  • Upload date:
  • Size: 26.4 kB
  • Tags: Source
  • Uploaded using 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}

File hashes

Hashes for isitdisposable-0.1.1.tar.gz
Algorithm Hash digest
SHA256 24d334c846a6a6aeb03ef0354dbe5288e2e50028be409033ee4e664137690866
MD5 9048ec08c5b77eec003241095ce3a04b
BLAKE2b-256 c9510b8708d28770a93dd9640c05af1dab32b30c80f770c45d10f87d93563673

See more details on using hashes here.

File details

Details for the file isitdisposable-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: isitdisposable-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 14.5 kB
  • Tags: Python 3
  • Uploaded using 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}

File hashes

Hashes for isitdisposable-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 df6c31570fc5906424b1c1be46be0609150b3af65f37b07aee33bcae3be742f9
MD5 a62add305b8b829e8dea6159a5bc7c82
BLAKE2b-256 0762f7e149c46b205f13adea1f4a26e65432b5bd91fb284094933ea7eb86f00d

See more details on using hashes here.

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