Introduction
There can be many reasons to send emails from a web server:
-
send a confirmation link upon user registration
-
send a password reset link
-
ask for confirmation on sensitive operations
-
send user-submitted content to a company email, e.g. for customer support or feedback
The Yada Framework approach to emails is similar to writing a web page: an html template is populated with values before being sent via a SMTP server you have configured. I18n is also available.
Configuration
The configuration file holds the SMTP server configuration and other parameters:
<email>
<enabled>true</enabled>
<from>mysender@gmail.com</from>
<logoImage>/template/email/mycompany-logo.png</logoImage>
<smtpserver>
<host>smtp.example.com</host>
<port>587</port>
<protocol>smtp</protocol>
<username>${smtpserver_username}</username>
<password>${smtpserver_password}</password>
<!-- If sendpartial is set to true, and a message has some valid and some invalid addresses, send the message anyway,
reporting the partial failure with a SendFailedException. If set to false (the default), the message
is not sent to any of the recipients if there is an invalid recipient address. -->
<properties>mail.smtp.sendpartial=true</properties>
<properties>mail.smtp.auth=true</properties>
<properties>mail.smtp.starttls.enable=true</properties>
<properties>mail.smtp.quitwait=false</properties>
<!-- Set this option to your mail server if you trust it and don't care checking the certificate validity, e.g. it is on your localhost
<properties>mail.smtp.ssl.trust=email-smtp.eu-central-1.amazonaws.com</properties>
-->
</smtpserver>
<!-- Remove this list to enable email to everyone -->
<validEmail>mydeveloper1@gmail.com</validEmail>
<validEmail>mydeveloper2@gmail.com</validEmail>
<!-- Email patterns of invalid emails (rejected on registration) -->
<blacklistPattern>.*invalid.*</blacklistPattern>
<blacklistPattern>.*@mailinator.com</blacklistPattern>
</email>
- enabled
-
when false or not set, emails are not sent
- from
-
email address of the sender, usually a system account. Can be repeated to have more sender emails.
- logoImage (optional)
-
path of the logo to place in the email, relative to the
resources
folder - host
-
SMTP server address
- port
-
SMTP server port
- protocol
-
SMTP server protocol
- username
-
SMTP server login username. The
${smtpserver_username}
value is a reference to a value stored in another configuration file, usually under/srv/xxx/bin/security.properties
- password
-
SMTP server login password. The
${smtpserver_password}
value is a reference to a value stored in another configuration file, usually under/srv/xxx/bin/security.properties
- properties (optional)
-
list of java mail properties
- validEmail (optional)
-
list of authorized destination emails. When present, all emails to addresses not listed here are not sent. Useful in development and test environments to prevent sending fake emails to real users
- blacklistPattern (optional)
-
Regex patterns of email addresses that are not accepted at registration
Email Templates
Email content is defined using HTML templates as for web pages.
Templates must be saved in the src\main\resources\template\email
folder as html files.
You can use most of the standard Thymeleaf notation, considering that neither the Model nor the HTTP request are available.
Singleton beans ${@mybean}
and localized strings #{my.local.string}
work as usual.
Includes can also be used, with a path relative to the templates
folder.
Model attributes must be set on a new Map<String, Object>
and can be accessed the usual way with ${myobj}
.
URLs need a special handling: the @{/myurl}
syntax doesn’t work because the server address is unknown to Thymeleaf, so
a "Model attribute" with the full URL must be used instead. The YadaWebUtil.getFullUrl()
method exists for this purpose.
Example src\main\resources\template\email\bookVisit.html
:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8"/>
<th:block th:replace="/email/mailhead :: head" ></th:block>
</head>
<body>
<th:block th:replace="/email/mailhead :: body" ></th:block>
<h1>Booking confirmed</h1>
<table>
<tr><td>Day: </td><td th:with="dateFormat=#{date.format.long}" th:text="${#dates.format(slot.start, dateFormat)}">10 january</td></tr>
<tr><td>Time: </td><td th:text="${slot.timeRange}">10:00 - 10:30</td></tr>
<tr><td>People: </td><td>[[${totPeople}]]</td></tr>
</table>
<p>Thank you for joining us.</p>
<p>If you need to cancel your booking, please <a th:href="@{${cancelLink}}">click here</a></p>
<div th:replace="/email/mailfooter :: body" ></div>
</body>
</html>
Email Subject
The subject of the email is localized and is defined in message.properties. The property name must have the format
email.subject.<templateName>
where <templateName>
is the name of the template html file without extension.
Example:
email.subject.bookVisit = Thank you for visiting {0}
Java Code
The YadaEmailService
class is the low level service to send emails,
both plain text and HTML, with attachments or inline images.
An easier API is provided by the YadaEmailBuilder
class.
public void confirmVisit(Booking booking, String customerEmail, File catalog, Locale locale) {
String cancelLink = yadaWebUtil.getFullUrl("/booking/cancel/", locale, "bookingId", booking.getId());
YadaEmailBuilder.instance("bookVisit", locale, yadaEmailService)
.to(customerEmail)
.from(config.getEmailFrom())
.addModelAttribute("slot", booking.getSlot())
.addModelAttribute("totPeople", booking.getTotPeople())
.addModelAttribute("cancelLink", cancelLink)
.subjectParams(booking.storeName())
.addAttachment(pdf.getName(), catalog)
.addInlineResources("logosmall", config.getEmailLogoImage())
.send();
}
Internationalization
The HTML of the email template can contain localized text expressed via the usual thymeleaf #{}
operator.
When you have emails with a lot of text, it may be more convenient to write the whole email in a specific language. Files for different languages other than the default one must have a _<lang> suffix. For example:
-
bookVisit.html
-
bookVisit_de.html
-
bookVisit_it.html