The official Python SDK for the Mailfloss email verification API. Zero runtime dependencies — standard library only.
- Full coverage of the Mailfloss v1 public API
- Automatic retries (429/5xx,
Retry-Afteraware, exponential backoff + jitter) - Automatic
Idempotency-Keyon every POST - Fully typed (
TypedDictmodels, shipspy.typed) - Python 3.9+
pip install mailflossGet your API key from the Mailfloss dashboard, then either pass it directly:
from mailfloss import Mailfloss
client = Mailfloss(api_key="mf_rk_your_key_here")or set it in the environment and construct the client with no arguments:
export MAILFLOSS_API_KEY="mf_rk_your_key_here"from mailfloss import Mailfloss
client = Mailfloss()Every request is sent with Authorization: Bearer <key>. If no key is
available, the constructor raises MailflossConfigError.
from mailfloss import Mailfloss
client = Mailfloss()
result = client.verify("jane@example.com")
print(result["status"]) # "passed" | "undeliverable" | "risky" | "unknown"
print(result["passed"]) # True if safe to send
print(result["reason"]) # e.g. "available", "nonexistent", ...
if result.get("suggestion"):
print("Did you mean:", result["suggestion"])job = client.batch_verify.create(
emails=["jane@example.com", "joe@exmaple.com"],
webhook_url="https://example.com/hooks/mailfloss", # optional callback
)
job_id = job["id"]
# Poll progress...
status = client.batch_verify.status(job_id)
print(status["status"], status.get("progress"))
# ...then page through results
page = client.batch_verify.results(job_id, per_page=500)
for row in page.get("results", []):
print(row)Non-2xx responses raise MailflossError with structured fields:
from mailfloss import Mailfloss, MailflossError
client = Mailfloss()
try:
client.jobs.get("does-not-exist")
except MailflossError as err:
print(err.status) # 404
print(err.code) # stable machine-readable code
print(err.message) # human-readable message
print(err.type) # e.g. "not_found_error"
print(err.request_id) # for support correlationRequests failing with 429 or 5xx (and connection errors) are retried
automatically up to max_retries (default 3), honoring the server's
Retry-After header when present.
| Resource | Methods |
|---|---|
| Single verify | client.verify(email, timeout=None) |
| Batch verify | client.batch_verify.create(emails, webhook_url=None) / .status(id) / .results(id, per_page=None, next=None) / .cancel(id) |
| Jobs | client.jobs.list(per_page=None, cursor=None, source=None, status=None) / .get(id) |
| Users | client.users.list(per_page=None, cursor=None) / .get(user_id) |
| Reports | client.reports.usage(period=None, connection_id=None) |
| Key check | client.check_key() |
| Account | client.account.get() / .update({...}) |
| Organization | client.organization.get() |
| Integrations | client.integrations.list() / .get(type) |
| Connections | client.integrations.connections.create(type, credentials, name=None) / .get(type, id) / .update(type, id, {...}) / .delete(type, id) / .sync(type, id) / .test(type, id) |
| Keyword rules | client.integrations.keywords.list(type, connection_id, list) / .add(type, connection_id, list, rules) / .delete(type, connection_id, list, rule_id) |
| Erasures | client.erasures.create(emails, webhook_url=None) |
List endpoints return {"data": [...], "pagination": {"next_cursor", "has_more"}}.
client = Mailfloss(
api_key="mf_rk_...", # or MAILFLOSS_API_KEY
base_url="https://api.mailfloss.com/v1", # default
max_retries=3, # retries on 429/5xx/conn errors
timeout=30.0, # socket timeout, seconds
transport=None, # injectable low-level transport
)Every POST automatically carries an Idempotency-Key header (UUIDv4),
generated once per call so retries replay the same key. Supply your own when
you want cross-process dedup:
client.batch_verify.create(
emails=["jane@example.com"],
idempotency_key="order-12345-verify", # gitleaks:allow — docs example, not a secret
)PYTHONPATH=src python3 -m unittest discover -s tests -vMIT — see LICENSE.