Overrides & theming

Three levels, most common first. Level 2 covers the majority of per-commune needs and touches no markup at all.

Level 1 — adjust the branding only

Three plone.app.registry records:

RecordUsed byDefault
imio.emailkit.theme.logo_urlthe layout headerempty
imio.emailkit.theme.primary_colorbuttons, header rulethe iMio magenta
imio.emailkit.theme.footer_htmlthe layout footerempty

logo_url and footer_html default to empty on purpose: a URL is site-specific, and footer wording is user-facing text, which the house convention leaves to i18n and to the site rather than freezing one language in a profile. An empty value collapses the block that would have used it.

The field defaults live in IEmailkitTheme and nowhere else — profiles/base declares the records from that interface and ships no values of its own, so a default is written once.

The design system itself is locked

Consumers compose the layout and components but do not extend the Tailwind config. That is what keeps every iMio product's mails recognisably the same. The three tokens above are the whole runtime-variable surface.

Level 2 — replace the markup, per site or per client

Register your own z3c.jbot directory on your site package's browser layer.

from imio.emailkit.interfaces import IEmailkitLayer


class IMyCommuneLayer(IEmailkitLayer):
    """This commune's browser layer."""
<include package="z3c.jbot" />
<browser:jbot directory="overrides" layer=".interfaces.IMyCommuneLayer" />

Override files are named after the dotted path of the file they shadow, e.g.

Products.CMFPlone.browser.login.templates.mail_password_template.pt

That is how you replace the password-reset and registration mails, because those are jbot overrides of stock Plone templates. The username reminder is a registered template rather than a jbot override, so you shadow it the way you shadow any registered template — imio.emailkit.templates.get_username.pt — and the same layer rule below applies.

Two traps, both silent

Because of that second trap: when you test an override, assert on rendered output, never only that a file was resolved.

Level 3 — opt out entirely

Install imio.emailkit:base instead of :default. You keep the API, the discovery and the kit; Plone's own mails are left exactly as they were.

PROFILE=base make create-site

The mechanism is the browser layer: the jbot directory is bound to IEmailkitLayer, which only :default installs, so the overrides are inert without it.

What is deliberately not offered

  • MailHost monkey-patching to re-skin arbitrary outgoing MIME. It breaks on the first calendar invite or signed message, and it is undebuggable.
  • A composable Tailwind preset. Revisit only if two products turn out to need genuinely different shells — and then a second layout in the kit is the cheap first answer.