5 min read

Sending HTML emails using Thymeleaf and Spring Boot

September 07, 2020

Things got easier with spring boot and thymeleaf. As you know, Thymeleaf is used as a View in Spring MVC applications. But do you know you can use the same template Engine for generating rich HTML emails? Let’s take a look at this example.

To achieve this, we need two starters from spring boot. Including the below to our pom.xml will enable JavaMail and Thymeleaf support for our project.

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

For My example I have also included spring-boot-starter-web so that I can trigger the emails via an API call. But its up to you on how you want to wire this in your own application.

By including the above dependencies, You are letting Spring Boot to configure the javamail and thymeleaf template Engine configurations. For Thymeleaf, you don’t need to add any additional configurations to your project. But JavaMail expects few configuration in order to initiate the JavaMailSender
object via auto configuration. A sample configuration is given below.

spring.mail.username=springhow.com@gmail.com
spring.mail.password=*******
spring.mail.host=smtp.gmail.com
spring.mail.port=587
spring.mail.protocol=smtp
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true

Note that I have used GMAIL’s SMTP server and my own username and password for this demo. In most of the cases, you are developing for an organization and would need to change the host based on your organization’s settings.

If you wish to use your own GMAIL account, then you may need to enable access for less secure apps for your account

Lets test this setup with a simple EmailService.

@Service
public class EmailService {


    private final JavaMailSender javaMailSender;

    public EmailService(JavaMailSender javaMailSender) {
        this.javaMailSender = javaMailSender;
    }

    public void sendMail(User user) throws MessagingException {
        javax.mail.internet.MimeMessage mimeMessage = javaMailSender.createMimeMessage();
        MimeMessageHelper helper = new MimeMessageHelper(mimeMessage);
        helper.setSubject("Welcome " + user.getName());

        String html = "<!doctype html>\n" +
                "<html lang=\"en\" xmlns=\"http://www.w3.org/1999/xhtml\"\n" +
                "      xmlns:th=\"http://www.thymeleaf.org\">\n" +
                "<head>\n" +
                "    <meta charset=\"UTF-8\">\n" +
                "    <meta name=\"viewport\"\n" +
                "          content=\"width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0\">\n" +
                "    <meta http-equiv=\"X-UA-Compatible\" content=\"ie=edge\">\n" +
                "    <title>Email</title>\n" +
                "</head>\n" +
                "<body>\n" +
                "<div>Welcome <b>" + user.getName() + "</b></div>\n" +
                "\n" +
                "<div> Your username is <b>" + user.getUsername() + "</b></div>\n" +
                "</body>\n" +
                "</html>\n";
        helper.setText(html, true);
        helper.setTo(user.getEmail());
        javaMailSender.send(mimeMessage);
    }
}

This code does its job well and has no problem except it is messy and hard to change in the future. When there are large emails with too many variables, This class will become a developer’s nightmare. Here comes thymeleaf for help.

Thymeleaf is most known for its use as a view in MVC applications. But it is basically a templating engine that generates content based a template and a set of context variables. So it is understandable to use the same technology for creating customized email content. That is exactly what we are going to do. Thanks to spring boot, This template engine is auto configured by default and no extra configuration is needed.

Thymeleaf by default picks up its templates from src/java/resources/templates/ directory. So let’s move our html template there and call it welcome.html.

<!doctype html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Email</title>
</head>
<body>
<div>Welcome <b th:text="${user.name}"></b></div>

<div> Your username is <b th:text="${user.username}"></b></div>
</body>
</html>

In my case, I have created a directory under templates called emails and placed my template file there. Now, Let’s re-write our EmailService by autowiring templateEngine. By eliminating the messy template part, the code becomes cleaner and easy to maintain.

@Service
public class EmailService {

    private final TemplateEngine templateEngine;

    private final JavaMailSender javaMailSender;

    public EmailService(TemplateEngine templateEngine, JavaMailSender javaMailSender) {
        this.templateEngine = templateEngine;
        this.javaMailSender = javaMailSender;
    }

    public String sendMail(User user) throws MessagingException {
        Context context = new Context();
        context.setVariable("user", user);

        String process = templateEngine.process("emails/welcome", context);
        javax.mail.internet.MimeMessage mimeMessage = javaMailSender.createMimeMessage();
        MimeMessageHelper helper = new MimeMessageHelper(mimeMessage);
        helper.setSubject("Welcome " + user.getName());
        helper.setText(process, true);
        helper.setTo(user.getEmail());
        javaMailSender.send(mimeMessage);
        return "Sent";
    }
}

For the demo, I have written an API that takes an user object and calls EmailService.sendMail(User user).

    @RequestMapping(value = "/email", method = RequestMethod.POST)
    @ResponseBody
    public String sendMail(@RequestBody User user) throws MessagingException {
        emailService.sendMail(user);
        return "Email Sent Successfully.!";
    }

If you have done all of the above properly, then you would get the following as the result.

$ curl -X POST "http://localhost:8080/email" \
  -H "Content-Type: application/json" \
  --data '{ "name": "John Doe",  "username": "jd01",  "email": "john.doe@yopmail.com" }'

HTTP/1.1 200 
Content-Type: text/plain;charset=UTF-8
Content-Length: 25
Date: Tue, 08 Sep 2020 09:17:06 GMT
Keep-Alive: timeout=60
Connection: keep-alive

Email Sent Successfully.!

You can also see the email at the disposable email box john.doe@yopmail.com.

Email received at john.doe@yopmail.com

Note that You can further improve this service by adding a new parameter for template name in the sendEmail method.

public void sendMail(User user, String templateName)

This way similar templates can use same method. For instance, User addition, deletion and modification can use same user object with different template files.

What do you think of this implementation? Do you have any doubts? Comment below.

Raja Anbazhagan

About the author

Raja is a Software Engineer with over 7 years of experience in working with Enterprise Java applications. Lately, He is focused in cloud-based Java applications and serverless technologies. He spends his spare time in stackoverflow.

Browse Categories