The shared HTML layout every email built from a file or a default is wrapped in.
PhoenixKit.Email.Content.resolve/5 calls wrap/3 on the file/default path,
so an email reaches the reader as HTML even when all it has is text: core's
auth emails and the defaults a module passes to
PhoenixKit.Mailer.send_from_template/4 ship no html part of their own.
Content from a database template is never wrapped — it carries its own
chrome.
The default is a function, like every other default
default_html/0 is core's layout, kept in code for the same reason the
message defaults are Gettext calls rather than files: core ships no files of
its own. It is deliberately neutral — the site's name above the body, the
name and a link to the site below it, table markup with inline styles, no
brand colours and no external resources. It carries no words of its own,
so it needs no translation: everything it prints is the site's name, its URL
and the message itself.
Overriding it
The layout is resolved like any other template, under the reserved name
_layout, so a host replaces it with an ordinary override file:
<host>/priv/phoenix_kit_templates/
└── _layout/
├── html.html <- every locale
└── html.de.html <- German readersLocale selection, roots and caching are exactly those of the message itself
(PhoenixKit.Templates). The layout's subject and text parts are never
read. Finding a file under a name that starts with _ needs
phoenix_kit_templates 0.2.1 or later; older releases skip such names and
core's default is used.
A layout with no content placeholder (an empty file, a typo such as
{{{contnet}}}) would drop the body of every email, so it is refused:
core's default is used instead, and a warning is logged once per override
roots and locale for the life of the VM.
Variables
| placeholder | value |
|---|---|
{{{content}}} | the message body, already HTML |
{{subject}} | the message subject, for <title> |
{{site_name}} | PhoenixKit.Settings.get_project_title/0 |
{{site_url}} | PhoenixKit.Utils.Routes.base_url/0 |
site_url is whatever the site is configured with. Core's default links it
only when it is an http(s):// address and prints it as text otherwise.
content must be written with three braces. The html part escapes
every {{variable}}, which is right for subject and the site's name but
would print the body's markup as visible text. Triple braces are the
escaping opt-out, and the body is safe to insert raw because it was escaped
when it was built — by the html part's own substitution, or by
text_to_html/1.
Opting out
layout: false to Content.resolve/5 or Mailer.send_from_template/4
leaves the message exactly as resolved. An html part that is already a
whole document is never wrapped either — an export of an old database
template is one. It is a document when, after any byte-order mark,
whitespace, <!-- comments --> and <?xml … ?> prolog, it starts with
<!doctype or an <html tag (<html>, <html lang="…">), in any case.
Summary
Functions
Core's layout: a header with the site's name, the body, and a footer with the name and a link to the site.
Whether html is a whole document rather than a fragment to wrap.
The reserved template name the layout resolves under.
Plain text as an HTML fragment.
Wraps an HTML fragment in the layout for this message's locale.
Functions
Core's layout: a header with the site's name, the body, and a footer with the name and a link to the site.
Options
:locale— becomes the document'slangattribute when it is a well-formed language tag (pt_BRis writtenpt-BR); omitted otherwise.:link—falseprints{{site_url}}in the footer as text instead of a link. Defaulttrue.
Whether html is a whole document rather than a fragment to wrap.
Leading byte-order marks, whitespace (non-breaking included), comments and
an XML prolog are skipped before looking for <!doctype or <html.
@spec name() :: String.t()
The reserved template name the layout resolves under.
Plain text as an HTML fragment.
Every character of text is escaped. A blank line separates paragraphs,
each a <p>; a single line break becomes <br>. An http:// or https://
address becomes a link. It ends at <, >, ", any Unicode whitespace or
separator, any invisible format character (zero-width spaces and joiners,
the soft hyphen, the byte-order mark, bidirectional controls — which could
otherwise make a link display a different address from the one it opens),
guillemets, the em dash and the punctuation after it up to the ellipsis
(U+2014–U+2027: typographic quotes, … and the like), and CJK/fullwidth
punctuation. Hyphens and the en dash do not end it, since real addresses
carry them. Trailing sentence punctuation and unbalanced closing
parentheses stay outside it. No other scheme becomes a link, so
javascript: and friends remain text, and neither does an address longer
than 2048 bytes.
Wraps an HTML fragment in the layout for this message's locale.
subject may be nil. Options are the message's own :locale and :paths,
so the layout resolves from the same override roots and for the same reader
as the message it wraps.