1. Overview
In our previous article, we saw how to use Spring to write and send text emails.
But it's also possible to use Spring template engines to write beautiful HTML emails with dynamic content.
In this tutorial, we're going to learn how to do it using the most famous of them: Thymeleaf and FreeMarker.
2. Spring HTML Emails
Let's start from the Spring Email tutorial.
First, we'll add a method to the EmailServiceImpl class to send emails with an HTML body:
private void sendHtmlMessage(String to, String subject, String htmlBody) throws MessagingException { MimeMessage message = emailSender.createMimeMessage(); MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8"); helper.setTo(to); helper.setSubject(subject); helper.setText(htmlBody, true); emailSender.send(message); }
We're using MimeMessageHelper to populate the message. The important part is the true value passed to setText method: it specifies the HTML content type.
Let's see now how to build this htmlBody using Thymeleaf and FreeMarker templates.
3. Thymeleaf Configuration
Let's start with our Spring @Configuration annotated class. In the sample code, we'll isolate it in EmailConfiguration class.
First, we should provide the template resolver by specifying the template files directory:
@Bean public SpringResourceTemplateResolver thymeleafTemplateResolver() { SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver(); templateResolver.setPrefix("/WEB-INF/views/mail/"); templateResolver.setSuffix(".html"); templateResolver.setTemplateMode("HTML"); templateResolver.setCharacterEncoding("UTF-8"); return templateResolver; }
Then, we have to provide the factory method for the Thymeleaf engine:
@Bean public SpringTemplateEngine thymeleafTemplateEngine() { SpringTemplateEngine templateEngine = new SpringTemplateEngine(); templateEngine.setTemplateResolver(thymeleafTemplateResolver()); return templateEngine; }
4. FreeMarker Configuration
In the same fashion as Thymeleaf, in the EmailConfiguration class, we'll configure the template resolver for FreeMarker templates (.ftl):
@Bean public FreeMarkerViewResolver freemarkerViewResolver() { FreeMarkerViewResolver resolver = new FreeMarkerViewResolver(); resolver.setSuffix(".ftl"); return resolver; }
And this time, the templates path will be configured in the FreeMarkerConfigurer bean:
@Bean public FreeMarkerConfigurer freemarkerConfig() { FreeMarkerConfigurer freeMarkerConfigurer = new FreeMarkerConfigurer(); freeMarkerConfigurer.setTemplateLoaderPath("/WEB-INF/views/mail"); return freeMarkerConfigurer; }
5. Localization with Thymeleaf and FreeMarker
In order to manage translations with Thymeleaf, we can specify a MessageSource instance to the engine:
@Bean public ResourceBundleMessageSource emailMessageSource() { ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource(); messageSource.setBasename("/mailMessages"); return messageSource; }
@Bean public SpringTemplateEngine thymeleafTemplateEngine() { ... templateEngine.setTemplateEngineMessageSource(emailMessageSource()); ... }
Then, we'd create resource bundles for each locale we support:
src/main/resources/mailMessages_xx_YY.properties
As FreeMarker proposes localization by duplicating the templates, we don't have to configure messages source there.
6. Thymeleaf Emails Templates
Next, let's have a look at the template-thymeleaf.html file:
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> </head> <body> <p th:text="#{greetings(${recipientName})}"></p> <p th:text="${text}"></p> <p th:text="#{regards}"></p> <p> <em th:text="#{signature(${senderName})}"></em> <br /> </p> </body> </html>
As can be seen, we've used Thymeleaf notation, that is, ${…} for variables and #{…} for localized strings.
As the template engine is correctly configured, it's very simple to use it: We'll just create a Context object that contains template variables (passed as a Map here).
Then, we'll pass it to the process method along with the template name:
@Autowired private SpringTemplateEngine thymeleafTemplateEngine; @Override public void sendMessageUsingThymeleafTemplate( String to, String subject, Map<String, Object> templateModel) throws MessagingException { Context thymeleafContext = new Context(); thymeleafContext.setVariables(templateModel); String htmlBody = thymeleafTemplateEngine.process("template-thymeleaf.html", thymeleafContext); sendHtmlMessage(to, subject, htmlBody); }
Now let's see how to do the same thing with FreeMarker.
7. FreeMarker Emails Templates
As can be seen, FreeMarker's syntax is more simple, but again it does not manage localized strings. So here's the English version:
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> </head> <body> <p>Hi ${recipientName}</p> <p>${text}</p> <p>Regards,</p> <p> <em>${senderName} at Baeldung</em> <br /> </p> </body> </html>
Then, we should use FreeMarkerConfigurer class to get the template file, and finally FreeMarkerTemplateUtils to inject data from our Map:
@Autowired private FreeMarkerConfigurer freemarkerConfigurer; @Override public void sendMessageUsingFreemarkerTemplate( String to, String subject, Map<String, Object> templateModel) throws IOException, TemplateException, MessagingException { Template freemarkerTemplate = freemarkerConfigurer.createConfiguration() .getTemplate("template-freemarker.ftl"); String htmlBody = FreeMarkerTemplateUtils.processTemplateIntoString(freemarkerTemplate, templateModel); sendHtmlMessage(to, subject, htmlBody); }
To go further, we'll see how to add a logo to our email signature.
8. Emails With Embedded Images
Since it's very common to include images in an HTML email, we'll see how to do this using a CID attachment.
The first change concerns the sendHtmlMessage method. We have to set MimeMessageHelper as multi-part by passing true to the second argument of the constructor:
MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8");
Then, we have to get the image file as a resource. We can use the @Value annotation for this:
@Value("classpath:/mail-logo.png") Resource resourceFile;
Notice that the mail-logo.png file is in the src/main/resources directory.
Back to the sendHtmlMessage method, we'll add resourceFile as an inline attachment, to be able to reference it with CID:
helper.addInline("attachment.png", resourceFile);
Finally, the image has to be referenced from both Thymeleaf and FreeMarker emails using CID notation:
<img src="cid:attachment.png" />
9. Conclusion
In this article, we've seen how to send Thymeleaf and FreeMarker emails, including rich HTML content.
To conclude, most of the work is related to Spring; therefore the use of one or the other is quite similar for a simple need such as sending emails.
As always, the full source code of the examples can be found over on GitHub.