Skip to main content

mailfixture

Email fixtures for your test suite. Create a programmatic inbox in one call, point your app's signup / OTP / password-reset flow at it, then wait for the email — parsed, with the OTP and links already extracted.

Receive-only, built for CI: long-polling instead of retry loops, zero dependencies outside the Python standard library, Python 3.9+.

pip install mailfixture

Quickstart

Create a key in Dashboard → API keys and export it as MAILFIXTURE_API_KEY.

from mailfixture import MailFixture

mfx = MailFixture()  # reads MAILFIXTURE_API_KEY

def test_signup_sends_otp(page):
    inbox = mfx.create_inbox(ttl_seconds=900)

    page.goto("/signup")
    page.fill("#email", inbox.email_address)
    page.click("text=Send code")

    otp = inbox.wait_for_otp(timeout=30)   # long-polls; no sleep()
    page.fill("#otp", otp)

Waiting for a magic link instead:

link = inbox.wait_for_link(kind="verify", timeout=30)
page.goto(link.url)

Capturing a webhook your app sends:

hook = mfx.create_hook(label="checkout", ttl_seconds=900)
configure_app_webhook(hook.ingest_url)  # your test setup
trigger_checkout()
request = hook.wait_for_request(match="body:order.created")
assert request.method == "POST"
hook.delete()

Everything on the wait helpers is server-side long-polling: the request is held open until a matching message arrives (or the timeout passes, raising mailfixture.MailFixtureTimeout).

API surface

Method Purpose
create_inbox(local_part=, domain=, ttl_seconds=) new inbox; returns an Inbox handle
inbox.wait_for_message(match=, timeout=) first matching message, full body + extraction
inbox.wait_for_otp(match=, timeout=) best extracted OTP as a string
inbox.wait_for_link(kind=, match=, timeout=) first link, optionally verify|reset|unsubscribe
inbox.messages(since=, match=, wait=) / clear() / delete() raw listing & lifecycle
get_message(id), get_otp(id), get_links(id) direct message access
download_attachment(message_id, index) decoded attachment bytes
create_hook(label=, ttl_seconds=), list_hooks() webhook capture URL and lifecycle handles
hook.wait_for_request(match=, since=, timeout=) first matching captured request, including full headers and body
hook.requests(...), clear(), delete() / get_hook_request(id) capture listing, teardown, and direct detail access
create_domain(fqdn), verify_domain(id), list_domains(), delete_domain(id) custom domains
create_key(label=), list_keys(), revoke_key(id) API keys

match filters with subject:, from:, or to: prefixes; a bare term matches the subject.

Capture-hook matching accepts method:, path:, and body:; a bare term matches the first 32 KiB of request body bytes. Returned detail bodies are complete.

Errors are raised as mailfixture.MailFixtureError carrying the API's RFC 7807 status / title / detail fields.

Development

PYTHONPATH=src python3 -m unittest discover -s tests

Docs: https://mailfixture.com/docs

Metadata

Release files for mailfixture 0.6.0

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

Source distribution (sdist)

Source distribution for mailfixture 0.6.0
File Size Uploaded
mailfixture-0.6.0.tar.gz 20.3 kB Details

Built distribution (wheel)

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

Total release size: 34.7 kB

Release files / mailfixture-0.6.0.tar.gz

Download URL mailfixture-0.6.0.tar.gz
Size 20.3 kB
Tags Source
SHA-256 checksum
How to use checksums
3bdbc85c242dd554a121dce1c3f1ea73e6d5cddb74eb6a8813abc6fd9b7f8314
BLAKE2b-256 checksum
How to use checksums
3ab3bf0802261f5220fb90570c2f8ef70eaffe8de4a3f65764af2ff851a8543a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.26 {"installer":{"name":"uv","version":"0.11.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / mailfixture-0.6.0-py3-none-any.whl

Download URL mailfixture-0.6.0-py3-none-any.whl
Size 14.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
2afcc8d0f63c44624623bd1441a7cf263ea9fa8a9b717d77b91e23fd83ef0217
BLAKE2b-256 checksum
How to use checksums
7910a0c560f058f7a2bee7aa5df05461d2a6721811f63fa4c32635f061a58347
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.26 {"installer":{"name":"uv","version":"0.11.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","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.6.0 This release

2 release files

0.5.0

2 release files

0.4.1

2 release files

0.4.0

2 release files

0.2.0

2 release files

0.1.0

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