Migrating a mail you already send

If your add-on already builds an HTML body — a notification assembled by string concatenation, say — you do not have to re-author it as a kit template to get the styled shell. There are two routes, and neither adds any API.

Route 1 — you already own your sending code

from imio.emailkit import render_shell

html, text = render_shell("Point 'Budget 2026' : état modifié", legacy_body_html)

render_shell drops legacy_body_html into the kit shell's body_html slot and returns the same (html, text) pair render() does. The shell contributes the whole document: inlined CSS, accessibility defaults, lang, the header and footer, the theme tokens and dark mode.

Your body goes in byte-for-byte — nothing is sanitised, reformatted or rewritten.

Route 2 — you want the Email builder (usually better)

from imio.emailkit import Email

Email("imio.emailkit:notification").to(member).with_context(
    title=subject, body_html=legacy_body_html
).send()

The kit layout defines the body_html slot for every template, not just the shell, so the builder can carry a legacy body too.

Prefer this when you can. You get per-language sending, recipient adapters, attachments and transaction-safe delivery, and you keep the registration's subject, its preheader and its hand-authored plaintext twin — none of which render_shell has.

What you do not change

Your existing markup, your existing data-gathering code, and your existing recipient logic if you take route 1. The shell wraps; it does not redesign.

One thing to check in your legacy body

Everything else about a legacy body survives: inline styles, bgcolor, nested tables, cellpadding, entities, unclosed tags, even a whole pasted <html> document. None of it raises — but a pasted full document does produce a nested <html>/<body>, which is invalid HTML that clients tolerate rather than something to rely on.

When to stop migrating and author properly

The shell buys you the frame. It cannot give you a real call-to-action button, a data table with screen-reader structure, a preheader, a decent plaintext twin, or per-language body copy — all of which are template-level features.

So: use render_shell to get every mail looking right this quarter, and author the ones that matter as kit templates when you next touch them. See Shipping templates.