1. Introduction
To create content of various e-mail and SMS notification user configurable a template engine is used. The Thymeleaf was selected. Please see following resources to get idea how to use it.
2. Templates
There are two types of templates.
Text (with .txt
suffix) and HTML (with .html
suffix).
Variables or processing instructions can be used inside of both template types.
Which exact variables can be used depends on exact use case.
See chapter Use cases to find out more.
Please note that content of all templates must be UTF-8 encoded. |
2.1. HTML
HTML templates must have *.html
suffix to be correctly recognized.
Most typical usage of HTML templates is e-mail body.
Advantage of using template engine is fast prototyping.
It allows to develop whole html page in any editor and preview it in standard web browser during development.
When the development is finished it can be easily integrated with PDM.control.
All tag processed by Thymeleaf starts with th:
and are ignored by web browser.
Then Thymeleaf replaces content of standard HTML tags based on those with th:
prefix.
Name of Thymeleaf tag usually corresponds with standard HTML tag.
E.g. src
→ th:src
, style
→ th:style
.
See documentation for more information.
2.1.1. Variables
Assume that we have variable name = "Jon" and age = 30. Then we can create following template.
My <span th:text="${name}">Jakob</span> is <span th:text="${age}">60</span> years old.
Such a template can be easily displayed in browser because unknown tags are ignored.
After processing it will became My friend Jon is 30 years old.
2.1.2. Conditions
A part of the template can be used only under certain condition. See Simple conditionals: "if" and "unless".
My friend
<span th:text="${name}">Jakob</span>
is
<span th:text="${age}">60</span>
years old
<span th:if="${age} < 30">and still young</span>
.
This will expand, depending on age
to following text.
-
age
< 30 ⇒My friend John is 30 year old and still young.
-
age
>= 30 ⇒My friend John is 30 year old.
2.1.3. Switch statement
Sometimes it is necessary to branch condition with switch statement especially in case of enumeration.
See Switch statements.
Assume that there is a variable animal which can be bird
, cat
or ant
.
My animal has got
<span th:swich="${animal}">
<span th:case="'bird'">2</span>
<span th:case="'cat'">4</span>
<span th:case="'ant'">6</span>
<span th:case="*">?</span>
</span>
legs.
Result of this template will depend on chosen animal. It will be
-
bird
⇒My animal has got 2 legs.
-
cat
⇒My animal has got 4 legs.
-
ant
⇒My animal has got 6 legs.
-
other ⇒
My animal has got ? legs.
2.1.4. Images
It is possible to use images together with HTML templates. There are three possible image references. They are briefly discussed in next chapters. More information can be found in article Embedding Images in HTML Email: Have the Rules Changed?
Linked images
It is possible provide link to the image hosted on some external server.
It is super easy and doesn’t impact the email size.
You just refer the image as a link in the HTML body with a simple img
tag:
<img src="/wp-content/uploads/2018/11/blog/-illustration-email-embedding-images.png?w=640" alt="img" />
Advantage:
-
it does not increase e-mail size.
Disadvantage
-
external images may be blocked by e-mail client.
PDM control support
PDM.control helps to resolve this case by serving all images found on user defined path pcon.mail.notification.template-path
under static path.
Always use variable ${imageURL}
to get this path.
Path it self may change in future releases.
<img src="mock.png" th:src="${imageURL + '/rtb_logo.png'">
URL encoding
Another way to display an image in the body of your message is to embed base64 image in HTML. It also refers to the MIME standard but here you don’t need to worry much about it. Base64 is a group of similar binary-to-text encoding schemes. If you want to know more about it, refer to Wikipedia since it has a comprehensive article on this topic.
To insert a picture to your email, you need to encode the image file as base64: use one of the many encoding services and then just paste base64 digits into HTML code like this:
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAZAAAADSCAMAAABThmYtAAAAXVB" alt="img" />
Disadvantage:
-
Such an encoding is totally blocked by Outlook
-
Limited support by clients.
-
Email message can become big because of 6bit encoding.
CID attachments, or embedding an image using MIME object
MIME (Multipurpose Internet Mail Extensions) is an Internet standard initially designed for SMTP that allows sending several content types (like HTML and text) in a single message body and supports non-text attachments like images.
It means that your message should contain at least two parts, HTML and plain text, which should be separated by defining boundaries. To embed an image, attach it and reference in the message body by setting its CID (Content-ID) and using a standard HTML tag:
<img src="cid:some-image-cid" alt="img" />
Advantage:
-
Displayed properly by clients
Disadvantage:
-
Email message can become big because image is part of the message.
PDM.control support
The help template designer to work with cid attached images, PDM.control offers automatic attachment of referenced image.
It is enough to put image name (without) path to src
tag and put the image to user defined location.
You can also use local depended imaged for customers for various regions.
For instance, we have such reference hit be request from local de_at
<img src="cid:logo.png" alt="logo" />
PDM.control will find appropriate image variant.
See chapter Localization and customization how it exactly works.
Found image is then automatically attached under cid:logo.png
.
2.2. Text
Text template must end whit .txt
suffix to be correctly recognized.
Most typical usage of text templates is for SMS or e-mail subjects.
2.2.1. Variables
Assume that we have variable name = "Jon" and age = 30. Then we can create following template.
My friend [(${name})] is [(${age})] years old.
Which will become text My friend John is 30 year old.
.
2.2.2. Conditions
A part of the template can be used only under certain condition.
My friend [(${name})] is [(${age})] years old [# th:if="${name} < 30"] and still young[/].
This will expand, depending on age
to following text.
-
age
< 30 ⇒My friend John is 30 year old and still young.
-
age
< 30 ⇒My friend John is 30 year old.
2.2.3. Switch statement
Sometimes it is necessary to branch condition with switch statement especially in case of enumeration.
Assume that there is a variable animal which can be bird
, cat
or ant
.
My animal has got
[# th:switch="${animal}"]
[# th:case="'bird'"]2[/]
[# th:case="'cat'"]4[/]
[# th:case="'ant'"]6[/]
[# th:case="*"]?[/]
[/]
legs.
Result of this template will be dependent on chosen animal. It will be
-
bird
⇒My animal has got 2 legs.
-
cat
⇒My animal has got 4 legs.
-
ant
⇒My animal has got 6 legs.
-
other ⇒
My animal has got ? legs.
2.2.4. Normalization
In some cases (E-mail subject and SMS) are text normalized. It means that multiple spaces and line ends are removed. In such a case following template definitions will produce equal result.
My friend
John
triggered is 30 years old.
My friend John triggered is 30 years old.
3. Localization and customization
User resources have to be put to a directory on file system.
Its location has to be provided as a a value of property pcon.mail.notification.template-path
in configuration file (or as command line argument), see documentation.
Resource files can be provided in localized from, distinguished by resource localization suffix.
For instance, we have a resource file logo.png
.
It can be provided for multiple locales like this.
-
logo_de_DE.png
- logo for German language in Germany -
logo_de_AT.png
- logo for German language in Austria -
logo_de.png
- logo for German language in all other regions -
logo_it.png
- logo for Italian language in all regions -
logo.png
- default logo for all other languages.
PDM.control searches for the most local specific variant witch matches the required locale. First user and then default location is scanned.
This technique is valid not only for images but also for templates itself.
It there is template like status_forwarding_subject.txt
required it is also possible to provide any local variant like status_forwarding_subject_de_at.txt
, status_forwarding_subject_de_de.txt
, status_forwarding_subject_it.txt
…
4. Use cases
4.1. Common variables
In each section below is defined set of variables which can be used for that specific use case. However there is also set of variables which can be used in any use case.
Variable | Description |
---|---|
|
Base URL to the server. It has to be defined in configuration ( |
|
Name of server which generated the message. It is either taken from configuration ( |
|
Full of URL PDM.control application of server which generated the message. |
|
URL from which the linked e-mail images can be loaded. |
4.2. Status forwarding
Status forwarding templates are defined in following files:
4.2.1. Variables
In status forwarding template following variables can be used. See also Common variables.
Variable | Description |
---|---|
|
Severity of alert. Can be |
|
Text of status message in rule’s language |
|
Number of status message |
|
Name of rule which triggered forwarding. |
|
URL of rule configuration. |
|
Name of PDM which caused status forwarding. |
|
Number of PDM which caused status forwarding. |
|
URL of PDM which caused status forwarding. |
|
Name of area where PDM belongs. |
|
Number of area where PDM belongs. |
|
URL of area where PDM belongs. |
|
Date and time of the event in rule’s time zone. |
4.2.2. Email subject
Email subject template must be stored in file status_forwarding_subject.txt
.
For example following templates can be used.
Forwarding rule [(${ruleName})] triggered on [(${serverName})].
You may of course use anything which was explain in chapter Text and create for instance template with different emojis based on alert type.
[# th:switch="${alertType}"]
[# th:case="'CRITICAL'"]💥[/]
[# th:case="'ERROR'"]❕❕[/]
[# th:case="'WARNING'"]❕[/]
[# th:case="*"]✔[/]
[/]
Forwarding rule [(${ruleName})] triggered on [(${serverName})].
Or just use and emoji in case of critical error
[# th:if="${alertType} == 'CRITICAL'"]💥[/]Forwarding rule [(${ruleName})] triggered on [(${serverName})].
Default template can be found in appendix.
4.2.3. Email body
Email body template must be stored in file status_forwarding_body.html
.
Default template can be found in appendix.
4.3. Logbook export
Status forwarding templates are defined in following files:
4.3.1. Variables
In status forwarding template following variables can be used. See also Common variables.
Variable | Description |
---|---|
|
URL where to download file from. |
|
Result file is attached. It is attached only if its size is smaller then value of |
|
Date and time of the event in rule’s time zone. |
4.3.2. Email subject
Email subject template must be stored in file logbook_export_subject.txt
.
It may of course used everything which was explained in chapter Text to create own with content.
Default template used in PDM.control can be found in appendix.
4.3.3. Email body
Email body template must be stored in file logbook_export_body.html
.
Default template used in PDM.control can be found in appendix.
Appendix A: Default templates
A.1. Status forwarding
A.1.1. Subject
[# th:switch="${alertType}"]
[# th:case="'CRITICAL'"]❌[/]
[# th:case="'ERROR'"]❕[/]
[# th:case="'WARNING'"]⚠[/]
[# th:case="'INFO'"]ℹ[/]
[# th:case="'NEW'"]🆕[/]
[# th:case="*"]✔[/]
[/]
Forwarding rule [(${ruleName})]
A.1.2. Body
Default e-mail body template provided with PDM control.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv=Content-Type content="text/html; charset=utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="PDM.control status message forwarding.">
<title>Status message forwarding</title>
<style>
td {
padding: 14pt;
}
p {
margin: 16px 0;
}
.alert-type {
font-size: 36.0pt;
padding: 10px 25px;
}
.text-center {
text-align: center;
}
.text-right {
text-align: right;
}
</style>
</head>
</head>
<body lang="EN_US" link="#0D6EFD" vlink="#954F72" style="word-wrap: break-word; font-family: 'Arial', sans-serif;">
<table style="border-collapse: collapse; table-layout: fixed; border: solid #E36600 3px; max-width: 726px;">
<colgroup>
<col style="width: 33%">
<col style="width: 34%">
<col style="width: 33%">
</colgroup>
<!-- Header -->
<tr>
<td style="font-size: 18pt;" colspan="2"><a href="#" th:href="${pconUrl}" style="color: #E36600;">PDM.control</a></td>
<td style="text-align: right;">
<img width=50 height=50 id="picRtbLogo" src="pdm_control_logo_small.png" th:src="|cid:pdm_control_logo_small.png|" alt="PDM.control logo">
</td>
</tr>
<!-- Alert type -->
<tr>
<td colspan="3" class="text-center" style="padding-top: 40px;">
<!-- Translate: Message type -->
<span th:if="${alertType} eq 'CRITICAL'" class="alert-type" style="color: white; background: #d63384">Critical error</span>
<span th:if="${alertType} eq 'ERROR'" class="alert-type" style="color: white; background: #dc3545">Error</span>
<span th:if="${alertType} eq 'WARNING'" class="alert-type" style="color: black; background: #ffc107">Warning</span>
<span th:if="${alertType} eq 'INFO'" class="alert-type" style="color: black; background: #0dcaf0">Info</span>
<span th:if="${alertType} eq 'NEW'" class="alert-type" style="color: black; background: fuchsia">New</span>
<span th:if="${alertType} eq 'NONE'" class="alert-type" style="color: white; background: #198754">OK</span>
</td>
</tr>
<!-- Status text-->
<tr>
<td colspan="3" style=" padding-top: 30px;" class="text-center">
<!-- Status name -->
<p>
<i style="font-size: 25pt" th:text="${statusText}">Technical door open</i>
</p>
<p>on PDM</p>
<p style="font-size: 15pt">
<span style="font-style: italic;" th:text="${pdmName}">Q-Bar (<span th:text="${pdmNumber}">5</span>)</span>
</p>
</td>
</tr>
<tr>
<td colspan="3" style=" padding-top: 20px;font-size: 14pt;">
<p style="text-align: justify; line-height: 1.5;">
<!-- Main Text -->
Status forwarding was caused by rule
<a href="#" th:href="${ruleUrl}" th:text="${ruleName}">Rule1</a>
triggered by message
'<i th:text="${statusText}">Technical door open</i>'
(<span th:text="${statusNumber}">55</span>)
on PDM
<a href="#" th:href="${pdmUrl}"><span style="white-space: nowrap;" th:text="${pdmName}">Q-Bar</span> (<span th:text="${pdmNumber}">5</span>)</a>
in area
<a href="#" th:href="${areaUrl}"><span style="white-space: nowrap;" th:text="${areaName}">RTB GmbH & Co. KG</span> (<span th:text="${areaNumber}">1</span>)</a>
.
</p>
</td>
</tr>
<!-- Date and time -->
<tr>
<td colspan="3" class="text-right">
—
<span style='font-size: 11pt; font-family: "Arial", sans-serif' th:text="${dateTime}">12.11.2021,
19:30:00</span>
</td>
</tr>
<!-- RTB footer -->
<tr>
<td colspan="3" style="padding: 60px 0 30px;">
<div style="margin: 0 5px;">
<img style="width: 100%;" id="pictureRtbFooter" src="rtb_footer.png" th:src="|cid:rtb_footer.png|" alt="RTB footer">
<p style="font-size: 11.0pt;" class="text-right">
<i style="font-size: 11pt;">Visit us on internet</i> >>>
<a href="www.rtb-bl.de"> www.rtb-bl.de</a>
</p>
</div>
</td>
</tr>
<!-- Signature -->
<tr style="font-size: 10pt; color: #212529;line-height: 1.3;">
<td style="vertical-align: top; padding-right: 0;">
Schulze-Delitzsch-Weg 10<br>
33175 Bad Lippspringe<br>
Deutschland<br>
<br><br><br>
Telefon: +49 5252 9706-206<br>
Telefax: +49 5252 9706-10<br>
E-Mail: <a href="mailto:parking-helpdesk@rtb-bl.de">parking-helpdesk@rtb-bl.de</a>
</td>
<td style="vertical-align:middle; padding: 0 5px;" class="text-center">
<img style="width: 100%; height: auto; min-width: 100px; max-width: 205px;" id="picRtbLogoSmall" src="rtb_logo.png" th:src="|cid:rtb_logo.png|" alt="RTB logo">
</td>
<td style="vertical-align: top; padding-left: 0;" class="text-right">
Kommanditgesellschaft<br>
Amtsgericht Paderborn HRA 2007<br><br>
Pers. haftende Gesellschafterin:<br>
RTB Beteiligungs GmbH<br><br>
Amtsgericht Paderborn HRB 2718<br>
Geschäftsführer:<br>
Rudolf Broer, Matthias Rieger
</td>
</tr>
</table>
</body>
</html>
A.2. Logbook export
A.2.2. Body
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv=Content-Type content="text/html; charset=utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="PDM.control logbook export is ready for download">
<title>Logbook export is ready</title>
<style>
td {
padding: 14pt;
}
p {
margin: 16px 0;
text-align: justify;
}
.text-center {
text-align: center;
}
.text-right {
text-align: right;
}
</style>
</head>
<body lang="EN_US" link="#0D6EFD" vlink="#954F72" style="word-wrap: break-word; font-family: 'Arial', sans-serif;">
<table style="border-collapse: collapse; table-layout: fixed; border: solid #E36600 3px; max-width: 726px;">
<colgroup>
<col style="width: 33%">
<col style="width: 34%">
<col style="width: 33%">
</colgroup>
<!-- Header -->
<tr>
<td style="font-size: 18pt;" colspan="2"><a href="#" th:href="${pconUrl}" style="color: #E36600;">PDM.control</a></td>
<td style="text-align: right;">
<img width=50 height=50 id="picRtbLogo" src="pdm_control_logo_small.png" th:src="|cid:pdm_control_logo_small.png|" alt="PDM.control logo">
</td>
</tr>
<!-- Export attached -->
<tr>
<td colspan="3" style=" padding-top: 30px;">
<p style="line-height: 1.7; margin-top: 0">
Your request has been processed and the result file is ready for download. Please click the link below to download requested file.
</p>
<p class="text-center" style="font-size: 2em; margin-top: 1em; margin-bottom: 1.5em;">
<a href="#" th:href="${downloadUrl}">DOWNLOAD</a><sup style="color: gray;">*</sup>
</p>
<p th:if="${fileIsAttached}">
For your convenience the result file is also attached to this e-mail.
</p>
<p th:if="not ${fileIsAttached}" style=" line-height: 1.5;">
Result file is not attached because it is bigger then maximal allowed size.
</p>
<p style="font-size: .8em; color: gray;">
<sup>*</sup> The file stays available for download within next 24 hours. After this period it will be deleted and
the link becomes invalid.
</p>
</td>
</tr>
<!-- Date and time -->
<tr>
<td colspan="3" class="text-right">
—
<span style='font-size: 11pt; font-family: "Arial", sans-serif' th:text="${dateTime}">12.11.2021,
19:30:00</span>
</td>
</tr>
<!-- RTB footer -->
<tr>
<td colspan="3" style="padding: 60px 0 30px;">
<div style="margin: 0 5px;">
<img style="width: 100%;" id="pictureRtbFooter" src="rtb_footer.png" th:src="${imageUrl + '/rtb_footer.png'}" alt="RTB footer">
<p style="font-size: 11.0pt;" class="text-right">
<i style="font-size: 11pt;">Visit us on internet</i> >>>
<a href="www.rtb-bl.de"> www.rtb-bl.de</a>
</p>
</div>
</td>
</tr>
<!-- Signature -->
<tr style="font-size: 10pt; color: #212529;line-height: 1.3;">
<td style="vertical-align: top; padding-right: 0;">
Schulze-Delitzsch-Weg 10<br>
33175 Bad Lippspringe<br>
Deutschland<br>
<br><br><br>
Telefon: +49 5252 9706-206<br>
Telefax: +49 5252 9706-10<br>
E-Mail: <a href="mailto:parking-helpdesk@rtb-bl.de">parking-helpdesk@rtb-bl.de</a>
</td>
<td style="vertical-align:middle; padding: 0 5px;" class="text-center">
<img style="width: 100%; height: auto; min-width: 100px; max-width: 205px;" id="picRtbLogoSmall" src="rtb_logo.png" th:src="|cid:rtb_logo.png|" alt="RTB logo">
</td>
<td style="vertical-align: top; padding-left: 0;" class="text-right">
Kommanditgesellschaft<br>
Amtsgericht Paderborn HRA 2007<br><br>
Pers. haftende Gesellschafterin:<br>
RTB Beteiligungs GmbH<br><br>
Amtsgericht Paderborn HRB 2718<br>
Geschäftsführer:<br>
Rudolf Broer, Matthias Rieger
</td>
</tr>
</table>
</body>
</html>