render()

The one way a registered template becomes text. render() is a pure function of template, context and registry state — no request faking, no site, no database. Previews, golden-file tests and the Email builder all go through this same door.

from imio.emailkit import render

html, text = render(
    "imio.pm.notifications:item_published",
    context={"item": item, "meeting": meeting},
    language="fr",
)

Signature

  • Name
    name
    Type
    str
    Description

    The namespaced template name, e.g. "imio.emailkit:notification". Raises TemplateNotFound if nothing is registered under it — carrying the list of names that are registered.

  • Name
    context
    Type
    mapping, optional
    Description

    Injected into the template namespace as top-level names, so a template reads ${item/title} and not ${options/item}.

  • Name
    language
    Type
    str, optional
    Description

    The language to render in. Defaults to the negotiated language.

Returns a (html, text) tuple.

What ends up in the namespace

Precedence runs low to high: the registration's preheader, then your context, then the names the package injects. The injected names win — a caller who shadowed theme or lang would break the shell, not just their own template.

  • Name
    lang
    Type
    str
    Description

    The render language. The kit layout emits it on <html>, so screen readers pick the right pronunciation.

  • Name
    theme
    Type
    mapping
    Description

    logo_url, primary_color, footer_html, read from plone.app.registry. A missing registry, a missing record and None all collapse to the empty string — the string "None" in a mail is worse than nothing.

  • Name
    preheader
    Type
    str
    Description

    The translated preheader msgid from the registration, if the template declared one. Rendered into the layout's hidden div.

  • Name
    portal_url
    Type
    str
    Description

    The portal's absolute URL, or "" when there is no request to build one from.

  • Name
    translate
    Type
    callable
    Description

    Translates a msgid into the render language.

  • Name
    format_date, format_datetime, format_number
    Type
    callables
    Description

    Locale-aware formatting, already bound to the render language. See the helpers.

  • Name
    target_language
    Type
    str
    Description

    Zope's page-template i18n machinery reads the render language from this name. Without it, i18n:translate negotiates from the request — that is, renders the wrong language, silently, whenever language was passed explicitly.

Locale helpers

Three callables, bound to the render language, so no template reinvents French date formatting — and half of them would get it wrong.

<td>${python: format_date(item.effective)}</td>
<td>${python: format_datetime(meeting.date)}</td>
<td>${python: format_number(amount)}</td>
Helperfren
format_date(value)12 août 2026August 12, 2026
format_datetime(value)12 août 2026 17:30August 12, 2026 5:30 PM
format_number(value)1 234,51,234.5

format_date and format_datetime take an optional length; format_datetime also takes time_length; format_number takes a pattern.

The plaintext part

If the template ships a hand-authored <name>.txt.pt twin, that is what you get. Without one, render() falls back to a naive text extraction of the HTML and logs a deprecation.

The twin is hand-authored on purpose. Maizzle's own plaintext output destroys tal: and i18n: constructs, so generating it would ship a plausible-looking body carrying the wrong content in the wrong language. See Testing.

Escaping

${...} values are HTML-escaped by Chameleon by default, which is the safe behaviour and the one you want. structure — unescaped insertion — is reserved for exactly two places: the shell's body_html slot and the footer_html theme token. Nothing else.