Sending HTML Emails with Thymeleaf in Spring applications

Spring May 16, 2020
Thymeleaf is a modern server-side Java template engine for both web and standalone environments.

Overview

We need to prepare html templates to be sent in the email as the content and use Thymeleaf to generate our content from template. Thymeleaf has variable expression support as ${variable} so the following HTML can be rendered dynamically with supplying the variables.

<!DOCTYPE html>

<html>

  <head>
    <title>Email Content</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  </head>

  <body>
  
    <p th:text="#{user.name}">Default body!</p>
  
  </body>

</html>

So if we look at the variable part:

<p th:text="#{user.name}">Default body!</p>

The th:text attribute, evaluates the value of the variable which is user.name and the value will be placed inside the body of the tag. So it will be rendered as

<p>{{user.name}}</p>

If the user.name variable is not set, then the default body which is Default body! in our example will be used as the content of the <p> tag.

So how we set these variables?

Configuring Thymeleaf

We can start with adding the dependency:

implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
build.gradle

Thymeleaf expects all the HTML templates to be placed under resources/templates folder. So we can design the HTML file that we want to send in the mail as a view and put it under this folder.

If you are lazy or not very good at CSS no worries a fast way to generate fancy HTML mail content might be using some ready templates, or designing with tools such as:

For instance Sendgrid has a very handy template design tool that you can export the HTML code after designing.

Sendgrid Template Design

Bare in mind that once your HTML code is ready, if you want to render dynamic content in it, you should add th:text attributes and the variable name to the tag as explained above.

And then we will create MailContentBuilder which will use the template engine to process our template with given parameters.

@Service
public class MailContentBuilder {

    private TemplateEngine templateEngine;

    @Autowired
    public MailContentBuilder(TemplateEngine templateEngine) {
        this.templateEngine = templateEngine;
    }

    public String generateMailContent(Client client) {
        Context context = new Context();
        context.setVariable("name", client.getName());
        context.setVariable("email", client.getEmail());
        context.setVariable("country", client.getCountry());
        context.setVariable("contact", client.getContact());
        
        return templateEngine.process("mailTemplate", context);
    }
}
MailContentBuilder.java

Template engine uses the given file name mailTemplate.html and processes it with the given context. Here the context object is an instance of Thymeleaf context and it used to store our parameters. So our variables in the HTML will be filled from these context.

Configuring Java Mail Sender

First we need to add the dependency for JavaMailSender

implementation 'org.springframework.boot:spring-boot-starter-mail'
build.gradle

We also need to configure our mail server to be able to send the mails. We can choose Gmail, Mailgun or any other mail server.

spring:
  mail:
    host: smtp.mailgun.org
    port: 587
    use-tls: true
    properties:
      mail:
        # enable debug logs for JavaMailServer
        debug: false
        smtp:
          auth: true
          starttls:
            enable: true

    username: "your-mail-address@provider.com"
    password: "your-password"
application.yml

We can send SimpleMailMessage or MimeMessage by JavaMailSender.

SimpleMailMessage models a simple mail message, including data such as the from, to, cc, subject, and text fields.

So for creating more sophisticated messages, for example messages with attachments, special character encodings, or html content we should use MimeMessage

@Component
public class MailSenderHelper {

    private final Logger logger = LoggerFactory.getLogger(MailSenderHelper.class);

    @Autowired
    private JavaMailSender emailSender;

    public void sendSimpleMail(String to, String from, String subject, String text) {
        SimpleMailMessage message = new SimpleMailMessage();
        message.setTo(to);
        message.setSubject(subject);
        message.setText(text);
        message.setFrom(from);
        emailSender.send(message);

        logger.info("Mail sent to: {}, with subject: {}", to, subject);
    }

    public void sendComplexMail(String[] to, String from, String subject, String text) {

        MimeMessage message = emailSender.createMimeMessage();
        MimeMessageHelper helper = null;
        try {
            helper = new MimeMessageHelper(message, true);


            helper.setFrom(from);
            helper.setTo(to);
            helper.setSubject(subject);
            helper.setText(text,true);

            emailSender.send(message);

            logger.info("Mail sent to: {}, with subject: {}", to, subject);

        } catch (MessagingException e) {
            logger.error(e.getMessage());
        }
    }
}
MailSenderHelper.java

We can use both methods to send emails but when we plan to send HTML content we can simply call use sendComplexMail:

public static void main(String[] args) {
		Client client = new Client("Cemal Turkoglu", "cemalturkogluiu@gmail.com", "Turkey");
        String message = mailContentBuilder.generateMailContent(client);
        String[] mailList = getSubscriberMailList();

        mailSenderHelper.sendComplexMail(
                    mailList,
                    "My Webpage Notification",
                    message
        );
    }
SendMailApplication.java
Great! You've successfully subscribed.
Great! Next, complete checkout for full access.
Welcome back! You've successfully signed in.
Success! Your account is fully activated, you now have access to all content.