Mailglass.Renderer (Mailglass v0.1.0)

Copy Markdown View Source

Pure-function render pipeline: HEEx → plaintext → CSS inlining → data-mg-* strip.

All functions are side-effect free. No processes, no DB, no HTTP calls.

Pipeline (D-15 — plaintext runs BEFORE CSS inlining)

  1. render_html/2 — calls Mailglass.TemplateEngine.HEEx.render/3, returns HTML iodata
  2. to_plaintext/1 — custom Floki walker on the pre-VML logical HTML
  3. inline_css/1Premailex.to_inline_css/2 (preserves MSO conditionals per D-14)
  4. strip_mg_attributes/1 — removes all data-mg-* from the final HTML wire

Plaintext MUST run on step-1 output (pre-CSS-inlining HTML), NOT on step-3 output. Premailex adds VML wrappers; the plaintext walker must not see them.

Performance Target

< 50ms end-to-end for a typical template (AUTHOR-03).

Boundary

Mailglass.Renderer cannot depend on Mailglass.Outbound, Mailglass.Repo, or any process. This is enforced by the :boundary compiler (CORE-07).

Summary

Functions

Renders a Mailglass.Message through the full pipeline.

Extracts plaintext from HTML using data-mg-plaintext strategy attributes.

Functions

render(message, opts \\ [])

(since 0.1.0)
@spec render(
  Mailglass.Message.t(),
  keyword()
) :: {:ok, Mailglass.Message.t()} | {:error, Mailglass.TemplateError.t()}

Renders a Mailglass.Message through the full pipeline.

Takes a Message whose swoosh_email.html_body is either a HEEx function component (fn assigns -> ~H"..." end) or a pre-rendered HTML string. Runs the configured pipeline and returns a Message with swoosh_email.html_body replaced by the final inlined HTML and swoosh_email.text_body populated with the auto-generated plaintext.

The entire pipeline is wrapped in Mailglass.Telemetry.render_span/2. Metadata is whitelisted to %{tenant_id, mailable} — no PII per D-31.

Examples

component = fn _assigns -> ~H|<p>Hello</p>| end
email = %Swoosh.Email{html_body: component}
message = Mailglass.Message.new(email, mailable: MyMailer)
{:ok, rendered} = Mailglass.Renderer.render(message)

to_plaintext(html)

(since 0.1.0)
@spec to_plaintext(String.t()) :: String.t()

Extracts plaintext from HTML using data-mg-plaintext strategy attributes.

Strategies (D-22):

  • "skip" — excludes the element and its children (preheader)
  • "link_pair" — emits "Label (url)" (button, link)
  • "divider" — emits "\n---\n" (hr)
  • "heading_block_1" — uppercase + blank lines (h1)
  • "heading_block_2" / "_3" / "_4" — title case + blank lines
  • "text" — raw text content; for <img>, uses the alt attribute
  • anything else (including missing) — recurses into children

Runs on the pre-VML logical HTML tree so VML artifacts never leak into plaintext output.