Skip to content

Commit ea18f45

Browse files
authored
Merge pull request #15745 from nextcloud/feat/email-template-docs
docs(mail): document the email template and its new blocks
2 parents cd13187 + 0e78d09 commit ea18f45

4 files changed

Lines changed: 133 additions & 0 deletions

File tree

‎admin_manual/configuration_server/email_configuration.rst‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,13 @@ settings and look the same in all the different email clients out there.
110110
Modifying the look of emails beyond the theming app capabilities
111111
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
112112

113+
.. warning:: Nextcloud 36 redesigned the email template: every email is now a single card,
114+
with dark mode and right-to-left support. A custom class overriding the HTML fragments of the
115+
previous design keeps working, but its parts will look out of place next to the new ones.
116+
Review it against the new ``EMailTemplate`` before upgrading. Calendar emails also no longer
117+
pass the ``meeting_*_html`` values to the template, they pass ``meeting_*_previous`` for
118+
changed values instead.
119+
113120
You can overwrite templates by writing a class that implements the template interface
114121
(or extends it to not need to copy over everything). Easiest way is to then put this class into
115122
an app and load it so you do not need to patch it on every update.

‎developer_manual/digging_deeper/email.rst‎

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,118 @@ The mailer is hidden behind the ``\OCP\Mail\IMailer`` interface that can be :ref
3737
}
3838
}
3939
40+
Email templates
41+
---------------
42+
43+
Most emails should not build their own HTML. ``IMailer::createEMailTemplate()`` returns an
44+
``\OCP\Mail\IEMailTemplate`` that renders a themed HTML email and a matching plain text version,
45+
with dark mode support for the mail clients that have it. Attach it to a message with
46+
``IMessage::useTemplate()``:
47+
48+
.. code-block:: php
49+
50+
$template = $this->mailer->createEMailTemplate('myapp.ProjectShared', [
51+
'project' => $projectName,
52+
]);
53+
$template->setLanguage($l->getLanguageCode());
54+
$template->setSubject($l->t('%s shared a project with you', [$sharerName]));
55+
$template->addHeader();
56+
$template->addHeading($l->t('%s shared a project with you', [$sharerName]));
57+
$template->addBodyText($l->t('You can now see and edit the project.'));
58+
$template->addBodyButton($l->t('Open project'), $projectUrl);
59+
$template->addFooter();
60+
61+
$message = $this->mailer->createMessage();
62+
$message->setTo([$recipientEmail]);
63+
$message->useTemplate($template);
64+
$this->mailer->send($message);
65+
66+
The first argument of ``createEMailTemplate()`` identifies the email (``<app>.<EmailName>``), and
67+
the second one passes data to custom templates (see `Modifying the look of emails
68+
<https://docs.nextcloud.com/server/latest/admin_manual/configuration_server/email_configuration.html>`_
69+
in the administration manual).
70+
71+
Write the email in the recipient's language: get an ``IL10N`` for their language from
72+
``\OCP\L10N\IFactory`` and pass its code to ``setLanguage()``. The template then sets the right
73+
``lang`` and ``dir`` attributes, mirrors the layout for right-to-left languages like Arabic or
74+
Hebrew, and writes the default footer in that language. Call it before ``addFooter()``.
75+
76+
Building blocks
77+
^^^^^^^^^^^^^^^
78+
79+
Since Nextcloud 36, the template has blocks to show who an email is about, a highlighted note, a
80+
card with details, and a row of buttons. Unlike ``addBodyText()`` with a separate plain text, these
81+
blocks never take HTML: every value is escaped by the template, URLs included, and each block
82+
writes its own plain text version.
83+
84+
.. figure:: ../images/email-template-blocks.png
85+
:alt: An email with a sender, a heading, a details card with a calendar badge, a description note, a warning note and three buttons
86+
:width: 500px
87+
88+
A sender, a details card, two notes and a row of buttons.
89+
90+
``addBodySender()``
91+
The person the email is sent for (sharer, organizer...), with an initials circle, their name
92+
and an optional second line such as their email address. Add it before the heading.
93+
94+
``addBodyNote()``
95+
A highlighted box. Use ``IEMailTemplate::NOTE_NEUTRAL`` (the default) for text written by a
96+
user, like a share note or an event description, with the label shown above it. Use
97+
``NOTE_INFO``, ``NOTE_WARNING`` or ``NOTE_ERROR`` for messages from the server, with the label
98+
as a bold title. Line breaks are kept.
99+
100+
``addBodyDetails()``
101+
A card describing an item: title, subtitle, an initials circle or a calendar badge, and
102+
labelled rows. See below.
103+
104+
``addBodyButtons()``
105+
Any number of buttons, the first one is the primary action, with an optional question above
106+
them like "Will you attend?".
107+
108+
The details card is built with ``\OCP\Mail\EMailDetails``. Each row holds one or more parts, each
109+
rendered on its own line: plain text, a link, or muted secondary text.
110+
111+
.. code-block:: php
112+
113+
use OCP\Mail\EMailDetails;
114+
use OCP\Mail\IEMailTemplate;
115+
116+
$template->addHeader();
117+
$template->addBodySender($organizerName, $organizerEmail);
118+
$template->addHeading($l->t('%s invited you to an event', [$organizerName]));
119+
120+
$details = (new EMailDetails($eventTitle))
121+
->setSubtitle($l->l('date', $start, ['width' => 'full']))
122+
->setDateBadge($l->l('date', $start, ['width' => '~MMM']), $l->l('date', $start, ['width' => '~d']));
123+
$details->addRow($l->t('Where'))
124+
->text($location)
125+
->link($l->t('Join in Nextcloud Talk'), $talkUrl);
126+
$details->addRow($l->t('Attendees'))
127+
->text($firstAttendee)
128+
->muted($l->n('and %n other', 'and %n others', $remaining));
129+
$template->addBodyDetails($details);
130+
131+
$template->addBodyNote($description, $l->t('Description'));
132+
$template->addBodyButtons([
133+
['text' => $l->t('Accept'), 'url' => $acceptUrl],
134+
['text' => $l->t('Decline'), 'url' => $declineUrl],
135+
], $l->t('Will you attend?'));
136+
$template->addFooter();
137+
138+
Use ``setInitials($name)`` instead of ``setDateBadge()`` to show an initials circle, for example
139+
for a conversation or a team. The badge strings are passed as is, so localize them yourself.
140+
141+
A short note about a shared item goes before its details card. Longer content, like an event
142+
description, goes after it.
143+
144+
Footer
145+
^^^^^^
146+
147+
``addFooter()`` without a text adds the default footer: the instance name and slogan, then
148+
"This is an automatically sent email, please do not reply.". When the email has a sender block,
149+
the second line becomes "This email was sent from <instance> on behalf of <name>." instead.
150+
Pass a text to ``addFooter()`` to replace the default footer entirely.
151+
40152
Inline attachments
41153
------------------
42154

71.3 KB
Loading

‎developer_manual/release_notes/new.rst‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,20 @@ This pages covers new features of the platform.
1111
Every feature should just have a brief description. Details have to be documented on a dedicated, persistent page.
1212
After branch-off the contents below will be cleared.
1313
14+
Email template blocks
15+
---------------------
16+
17+
The email template (``\OCP\Mail\IEMailTemplate``) was redesigned with dark mode and
18+
right-to-left support, and has new building blocks so emails no longer need hand-built HTML:
19+
20+
- ``addBodySender()`` shows who the email is about, with an initials circle.
21+
- ``addBodyNote()`` shows a highlighted note from a user, or an info, warning or error message.
22+
- ``addBodyDetails()`` shows a card with a title and labelled rows, built with ``\OCP\Mail\EMailDetails``.
23+
- ``addBodyButtons()`` shows any number of buttons.
24+
- ``setLanguage()`` sets the language of the email, which also mirrors the layout for right-to-left languages.
25+
26+
All values are escaped by the template. See :ref:`email` for details.
27+
1428
New ``\OCP\Files\IUserFolder`` API
1529
----------------------------------
1630

0 commit comments

Comments
 (0)