Skip to content

✨ Mailer: overridable layout and partials (header, footer, button, styles) #4132

Closed

Description

@PierreBrisorgueil

What

  • Add mailer.layout (a path) and mailer.partials (a { header, footer, button, styles } map of paths). Devkit ships the defaults in config/templates/_layout/, built on brand tokens: logo, colors, font, signature, contact footer and links.
  • render(key, params, { subject }) compiles the body, then the layout. The layout receives {{{body}}}, brand and subject, and subject fills <title>.
  • Use an isolated handlebars.create() instance, with partials registered from config.
  • Legacy passthrough: a template whose trimmed source starts with <!doctype or <html (case-insensitive) is sent unwrapped.
  • Layout and partial paths go through the resolver's containment check.

Acceptance criteria

  • A downstream replaces the whole layout, or a single partial, through its config only.
  • Full-document templates (all 15 today, plus any that exist only in a downstream) render byte-identical.
  • A body-only fragment gets the layout.
  • {{> button url=url label="..."}} is available to every template.
  • Nothing is registered on the global handlebars instance.

Tests

  • Wrap vs passthrough, including a leading-whitespace or uppercase doctype.
  • A partial override from a mocked downstream-shaped config.
  • Containment on layout and partial paths.
  • Escaping: params stay escaped and the body is injected once.

Depends on: resolver and brand.

Needs: #4129, #4130

Activity

  1. PierreBrisorgueil commented on Oct 2, 2026

    @PierreBrisorgueil
    ContributorAuthor

    WIP — session 20261002T193722Z-13C22542, branch feat/4132-mailer-layout-partials, started 2026-10-02T19:37:22Z

  2. PierreBrisorgueil commented on Oct 2, 2026

    @PierreBrisorgueil
    ContributorAuthor

    merged via drain (Automerge: absent, --review: false) — PR #4166. Reviewers: CodeRabbit (1 finding fixed) + Claude fallback on later heads (CodeRabbit rate-limited).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions