An email body written in Markdown, as HTML and as plain text.
PhoenixKit.Email.Content.resolve/5 uses this for a markdown part
(markdown[.<locale>].md): the HTML body comes from it when the message has
no html part, and the text body when it has no text part.
Placeholders
{{variable}} and {{{variable}}} work as in an html part: two braces
escape the value, three insert it raw. They are substituted after the
Markdown is rendered — a renderer percent-encodes {{url}} in a link
target, so a value substituted before it would arrive as %7B%7Burl%7D%7D,
and a value rendered as Markdown could change the markup around it. Each
placeholder is swapped for an opaque token, the Markdown is rendered and
sanitized (PhoenixKit.Utils.HtmlSanitizer), the placeholders are put back
and substituted with PhoenixKit.Templates.Substitution.
Links and buttons
Every link and image is built here rather than by the renderer, so its address is known after substitution:
- The address is the link target with its placeholders filled in, raw or not — inside an attribute both spellings are escaped as an attribute value.
- Only an
http://,https://ormailto:address (images:http(s)only) is kept. Anything else —javascript:, a relative path, a placeholder nothing bound — drops the link and keeps its label as text. - A paragraph that is exactly one
[label](url)link becomes a button: a table cell in the accent colour, which renders the same in every email client. A bare address on its own line stays a link. - Other links are coloured with the accent colour.
The accent colour is the accent_color variable, checked by
PhoenixKit.Email.Branding.normalize_color/1.
A paragraph that is only placeholders
A top-level paragraph of plain text whose placeholders all fill in blank —
{{failed_attempts}} on its own line, with nothing to report — is left
out of both bodies, rather than sent as an empty paragraph. A value that
is a sentence ending in a blank line, written as its own paragraph, stays
its own paragraph.
A paragraph that is exactly one {{{variable}}} is the value alone, with
no <p> around it — the way to place a block of HTML a caller built (a
table of invoice lines) between Markdown paragraphs. The text body
substitutes it as is, so a caller that passes HTML that way gives the
email a text part of its own.
Raw HTML
HTML written inside the Markdown is not rendered: a placeholder inside an
attribute of it could not be checked like a link target. A body that needs
markup of its own belongs in an html part.
Summary
Functions
markdown as a sanitized HTML fragment with variables substituted.
markdown as plain text with variables substituted.
Functions
@spec to_html(String.t(), PhoenixKit.Templates.Substitution.variables()) :: String.t()
markdown as a sanitized HTML fragment with variables substituted.
@spec to_text(String.t(), PhoenixKit.Templates.Substitution.variables()) :: String.t()
markdown as plain text with variables substituted.
Headings and paragraphs are lines separated by a blank line, list items
start with - (1. when numbered), [label](url) becomes
label: url — just url when the label is the address itself, as in
[{{url}}]({{url}}) — an image becomes its alt text, and emphasis, code
and raw HTML marks are dropped. A value that ends in blank lines never
leaves more than one blank line in a row.