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.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 django-mail-preview 0.2.1
File Size Uploaded
django_mail_preview-0.2.1.tar.gz 67.2 kB Details

Built distribution (wheel)

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

Total release size: 116.8 kB

Release files / django_mail_preview-0.2.1.tar.gz

Download URL django_mail_preview-0.2.1.tar.gz
Size 67.2 kB
Tags Source
SHA-256 checksum
How to use checksums
601a0935dd799ed90940c6e0d95c79551b9af4ed2bbdee093e36fa5e4750d2e5
BLAKE2b-256 checksum
How to use checksums
701f4d75ea288506651ea3f5ced583a348b38a850672d5ea3b4c6591d6316905
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.1-py3-none-any.whl

Download URL django_mail_preview-0.2.1-py3-none-any.whl
Size 49.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
ad1b33f616cb3b66c9e25f396a9d0f8393c0ad9a2fb437f4bc219dba3a06b94e
BLAKE2b-256 checksum
How to use checksums
30802ef5f4ae1af4b560f2f0e118075b8bf1ecc6aa294a9e85c8e7b8b488b0ee
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

This release

0.2.1 This release

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