Skip to main content

django-mail-preview

PyPI version Python versions CI Documentation

See every email your Django app sends, rendered in the browser, without sending a single one.

Checking email in a Django project usually means reading raw MIME in the console or sending real mail to a test inbox. django-mail-preview gives you one page inside the project instead: a capture email backend stores the mail your app sends, and preview classes build emails from sample data without sending them. The page answers 404 unless DEBUG is on, needs no staticfiles, and adds no models or migrations. Django is the only dependency.

A captured message rendered in a sandboxed frame at 600 px wide, with the previews grouped by app and the inbox in the sidebar, in the dark colour scheme

Quickstart

python -m pip install django-mail-preview

Add the app and the capture backend to your settings:

INSTALLED_APPS = [
    # ...
    "django_mail_preview",
]

# Django 6.1 and later
MAILERS = {
    "default": {"BACKEND": "django_mail_preview.backends.EmailBackend"},
}

# Django 5.2 and 6.0
EMAIL_BACKEND = "django_mail_preview.backends.EmailBackend"

Include the URLs:

from django.urls import include, path

urlpatterns = [
    # ...
    path("__mail-preview__/", include("django_mail_preview.urls")),
]

Open http://localhost:8000/__mail-preview__/. Every email the app sends from now on appears there, rendered in a sandboxed frame, with its plain text, source, headers and attachments a tab away. The include needs no if settings.DEBUG wrapper, because the views answer 404 unless DEBUG is on.

Previews

To see an email without triggering it, add a previews.py to any app. Each public method of an EmailPreview subclass builds one email from sample data:

# accounts/previews.py
from django_mail_preview import EmailPreview

from .emails import password_reset_email, welcome_email
from .models import User


class AccountEmails(EmailPreview):
    def password_reset(self):
        """Sent after the "forgot password" form."""
        user = User(first_name="Ada", email="ada@example.com")
        return password_reset_email(user)

    def welcome(self):
        return welcome_email(User(first_name="Ada"))

Refresh the page, and the sidebar lists password_reset and welcome under accounts. Previews are found by convention, rebuilt on every request and never imported in production. A query string on a preview's URL reaches it as self.params, so one method can show variants. One parametrised test renders every preview:

import pytest

from django_mail_preview import get_previews


@pytest.mark.parametrize("preview", get_previews(), ids=lambda preview: preview.id)
def test_preview_renders(preview):
    preview.render()

Compatibility

Python Django
3.10, 3.11 5.2
3.12, 3.13, 3.14 5.2, 6.0, 6.1

Security

The pages answer 404 unless DEBUG is True, and MAIL_PREVIEW_ALLOW replaces that rule with your own check for a staging server. Email HTML renders in a sandboxed frame under a Content Security Policy that lets images and styles load but never runs a script, and every attachment downloads instead of rendering in your site's origin.

Documentation

The full documentation is at django-mail-preview.readthedocs.io:

License

MIT.

Metadata

Release files for django-mail-preview 0.2.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 django-mail-preview 0.2.0
File Size Uploaded
django_mail_preview-0.2.0.tar.gz 67.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for django-mail-preview 0.2.0
File Interpreter ABI Platform
django_mail_preview-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 116.6 kB

Release files / django_mail_preview-0.2.0.tar.gz

Download URL django_mail_preview-0.2.0.tar.gz
Size 67.1 kB
Tags Source
SHA-256 checksum
How to use checksums
977fbc4df9160915fa3af2fdc8d9bf9b7528ac78d0c25dc4311da60bd460846b
BLAKE2b-256 checksum
How to use checksums
5e4972143ad6eb68a9ba23bc8cadd75078dd9d8cbdb8c44dbb6896cba8f06a6c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 3, 2026.

Transparency log

Release files / django_mail_preview-0.2.0-py3-none-any.whl

Download URL django_mail_preview-0.2.0-py3-none-any.whl
Size 49.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
31770ecd96c005ba44adf941e0db8e8c24cff1b510b706f43ce62ba3eb1b8c31
BLAKE2b-256 checksum
How to use checksums
581f3c6bc0078dbbb57712f41e40c83e29089c84d761519841d981ce6003d9e9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 3, 2026.

Transparency log

Release history Release notifications | RSS feed

0.2.2

2 release files

0.2.1

2 release files

This release

0.2.0 This release

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