Django templated email: compare both bodies

The HTML email can look correct while the plain-text body gives a different date. Compare both representations from the same context before considering delivery.

The worked notice preserves four facts in both bodies, including zero. The local HTML comparison starts with event W1, title Print & Review, date October 20, 2026 and remaining places 0. Changing the HTML-only date exposes a mismatch without pretending that a Django message or MIME tree has been constructed.

Django templated email: compare both bodies
Django templated email: compare both bodies
Open the full example ↗

Work through the example

The plain-text pane shows Print & Review literally; the HTML source pane uses Print & Review, while the reading pane shows the ordinary ampersand. Enter October 21, 2026 in the HTML-only date and Compare facts: the checker reports the disagreement. Restore October 20, 2026 to match all four visible values. Keep Django template rendering and message inspection as a separate native step.

Keep the raw HTML-escaping check separate from visible fact parity. A literal ampersand in text and an escaped ampersand in HTML source can convey the same title. Zero is a supplied value, not missing data. In Django, render both templates from the same explicit context, inspect the alternative message and decoded leaves, and stop before any sending operation.

Establish four facts shared by both templates

Use a fictional review event with these values:

Context key Supplied fixture value Required reading in both versions
event_code W1 Event code W1
title Print & Review Title Print & Review
event_date October 20, 2026 That same date
remaining 0 Remaining places: 0

Use subject W1 review notice, practice sender review@example.com, and practice recipient reader@example.com. These are illustrative header values for inspection, not real delivery destinations or a request to send anything.

A readable text body can state each fact on its own labeled line. The HTML counterpart can use a heading for the title and labeled paragraphs for the code, date, and remaining count. The layout may differ; the four facts must not. Treat zero as the supplied value, not as missing data that should trigger “available” or a blank.

Render separately from one explicit context

Django's email guide shows separate template rendering with render_to_string, followed by a text body and attached HTML alternative. This plan uses the same pattern while stopping before transmission. Django 6.0 email documentation

Use templates named emails/w1_notice.txt and emails/w1_notice.html. Both receive the same explicit four-key context. When rendering in Django, record the template engine, loader configuration, Django version, template revisions and context revision. Check the installed version before applying the linked 6.0 documentation.

Escaping needs separate treatment for the two formats. Django's template backend enables HTML autoescaping by default. Retain it in the HTML template; arrange the strictly plain-text template's rendering so HTML entity escaping does not turn its title into visible &. A scoped non-HTML rendering setting belongs to the text template only, not the HTML version. Template rendering and escaping settings

For this ordinary title string, the expected HTML source contains Print & Review, while its visible text reads Print & Review. The plain-text body should also read Print & Review. Raw HTML source and plain text need not be byte-for-byte equal. Check raw escaping and visible fact parity as two independent requirements.

Do not mark the title as trusted HTML or disable HTML escaping to make the two raw strings look identical. Likewise, do not assume a .txt filename alone changes the engine's escaping configuration. Inspect the rendered text body for the literal title.

Assemble an alternative message for inspection

Plan an EmailMultiAlternatives instance with the rendered text as its body and the fixed headers above. Add the rendered HTML using attach_alternative with text/html. For this no-attachment fixture, expect a top-level multipart/alternative containing two leaf parts: text/plain and text/html.

Recreate this example

Build one self-contained responsive HTML example titled “Django templated email: compare both bodies” for readers completing the stated task. Return the complete HTML with embedded CSS and JavaScript. Use no remote fonts, libraries, images, requests, account connections, or saved-state claims.

Use W1, Print & Review, October 20, 2026, remaining 0. Show original plain-text body, escaped HTML source and visible reading text. Labeled HTML-only date input and Compare facts button compare four visible facts; October 21 must report date mismatch and October 20 must match. Preserve zero. Render user values as text or escaped source. Include native recipe notes: render two templates from one context, EmailMultiAlternatives text body, attach HTML alternative, message() inspection without send. Label browser comparison as authored reference output, not Django/MIME execution.

Use a developer mail inspection bench with paired text/source panes design with a compact header. Keep the actual sample data, controls, and useful default result visible early on a 360px-wide screen. Use readable text at least 16px, generous paragraph spacing, strong contrast, semantic labels, visible keyboard focus, and wrapping source blocks. Stack records on narrow screens rather than forcing a wide table.

Wire each action to an explicit type=button click handler using element selectors; the host permits scripts but blocks form submission. Update the visible result when the described action occurs. Show specific error feedback for invalid or missing input and clear stale feedback after dependent inputs change. Use plain text when displaying user values.

This authored body comparison does not run Django, assemble MIME or send mail. Keep the source fixture and worked teacher or developer example distinct from actual user records. Include the domain-specific explanation and next check beside the result. Provide no fake download, send, deployment, approval, or persistence button. Everything operates locally for the current page session.

Review the prepared copy in NOS

Once both native representations are inspected, use their sanitized HTML reading comparison for a copy review in NOS. Eligible static explanatory wording can be edited visually; the Python templates, context and actual MIME inspection still need their own versioned evidence before delivery.

Keep reading