Send email in Spring Boot with Thymeleaf and Mailgun

Photo by Rowan Freeman / Unsplash
Photo by Rowan Freeman / Unsplash

Photo by Rowan Freeman / Unsplash

In a Web application, we use email to notify users of an event that requires their attention. Spring Boot makes it easy to add this feature to our back-end application.

One of the most classic workflows in web applications is the registration process, where a user submits his information. The back-end retrieves the input, saves It in the database, sends a confirmation email, and finally sends the response to the user.

As you guessed, we will focus only on sending the confirmation email. At the end of this post, you will learn how to create an HTML template email with Thymeleaf, embed a picture in an email, and send an email asynchronously with Spring Boot.

Build a One-time Password in Node.js using Twilio SMS API and Redis
In this post, we will see how to build a one-time password system in Node.js and Typescript using the Twilio SMS API and Redis.

Prerequisites

To follow this tutorial, you need the following tools:

Set up the project

We will use the Spring Boot starter website start.spring.io to create a boilerplate with the necessary dependencies.

Set up a new Spring Boot project
Set up a new Spring Boot project.
  • Click on generate to download the zip file, unzip and open it in your IDE.
  • Install Maven dependencies: mvn install
  • Run the application: mvn spring-boot run

I use IntelliJ from JetBrains, which installs dependencies automatically for me.

Build the email template

Thymeleaf is a server-side Java template engine for web and standalone environments making it easier to write dynamic content for web pages. It generates HTML and XHTML. If you want to learn more, check out the documentation.

Create a file registration.html in the folder resources/templates. Also, create a folder images containing the picture we want to include in the email content.

Registration email template location in the project structure.
Registration email template location in the project structure.

Add the code below to the file registration.html:


<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
  <title th:remove="all">Registration confirmation</title>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  <style type="text/css">
    body {
      font-family: calibri, 'DejaVu Sans', Arial, Helvetica, sans-serif;
    }
    a.link {
      border: solid 1px #000;
      background-color: #000;
      text-decoration: none;
      color: #fff;
      font-weight: bold;
      display: block;
      width: 360px;
      text-align: center;
      padding: 10px 0;
    }
  </style>
</head>
<body>
<h1>Confirm your account</h1>
<div>Welcome to AwesomeApp <b th:text="${name}">name</b> !</div>
<p>
  Your account has been created on our platform; here is your login information
  <br/><br/>
  Email address : <b th:text="${email}">email</b><br/>
  <br/>
  To confirm the validity of your email address, please click on the link below
</p>
<p style="text-align: left;">
  <a class="link" href="#" th:href="${url}">Confirm my account</a>
</p>
<br>
<p>
  <img src="images/spring.png" data-th-src="|cid:springLogo|" height="80" />
</p>
<p>
  Regards, <br />
  &emsp; <em>The AwesomeApp Team</em>
</p>
</body>
</html>

The picture spring.png inside the folder images is the logo of the Spring Framework.

Spring Framework logo.
Spring Framework logo.

Configure the view engine template

We need to indicate to the template engine (Thymeleaf) where to read and parse the files. For that, let's create a file TemplateEngineConfig.java inside a package configs.


package com.tericcabrel.mail.configs;

@Configuration
public class TemplateEngineConfig implements WebMvcConfigurer {
  private static final String EMAIL_TEMPLATE_ENCODING = "UTF-8";

  @Bean
  @Primary
  public TemplateEngine emailTemplateEngine() {
    final SpringTemplateEngine templateEngine = new SpringTemplateEngine();
    // Resolver for HTML emails (except the editable one)
    templateEngine.addTemplateResolver(emailTemplateResolver());

    return templateEngine;
  }

  private ITemplateResolver emailTemplateResolver() {
    final ClassLoaderTemplateResolver templateResolver = new ClassLoaderTemplateResolver();
    templateResolver.setResolvablePatterns(Collections.singleton("*"));
    templateResolver.setPrefix("/templates/");
    templateResolver.setSuffix(".html");
    templateResolver.setTemplateMode(TemplateMode.HTML);
    templateResolver.setCharacterEncoding(EMAIL_TEMPLATE_ENCODING);
    templateResolver.setCacheable(false);

    return templateResolver;
  }
}

Now we defined the custom configuration for the template engine, we need to disable the auto-configuration for Thymeleaf. Update the entry file:


@SpringBootApplication(exclude = { ThymeleafAutoConfiguration.class })
public class MailApplication {
	public static void main(String[] args) {
		SpringApplication.run(MailApplication.class, args);
	}
}

Configure STMP settings

To send an email, we need to set SMTP settings from a provider who is Mailgun, for our case. Here are the steps to find the SMTP credentials:

  • Login to your Mailgun account
  • In the sidebar menu, click on the dropdown menu "Sending."
  • Click on the submenu "Overview"
  • On the page displayed, you have two boxes, API and SMTP; click on the latter.
  • You will see a section with SMTP credentials.
SMTP credentials in the Mailgun dashboard
SMTP credentials in the Mailgun dashboard
Send email in Node.js using Handlebars and Amazon SES
In this post, we will see how to set up Amazon SES and send emails through SMTP in Node.js using Handlebars and Nodemailer.

Add SMTP settings in the Spring configuration file

Open the file application.properties and update with the code below:


spring.mail.host=smtp.mailgun.org
spring.mail.port=587
spring.mail.username=<mailgun_username>
spring.mail.password=<mailgun_password>
spring.mail.properties.mail.transport.protocol=smtp
spring.mail.properties.mail.smtp.starttls.enable=true
spring.mail.properties.mail.smtp.starttls.required=true
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.from=contact@tericcabrel.com
spring.mail.default-encoding=UTF-8
spring.mail.test-connection=false
mail.from.name=AwesomeApp

Note: The property spring.mail.test-connection when set to true, test the SMTP connection on application launch, which means if the connection fails, an error will be thrown, and thus prevent the Web application from starting.

Create an endpoint to test

Let's create a controller called UserController.java and add the code below:


package com.tericcabrel.mail.controllers;

@RestController
public class UserController {
  private static final String TEMPLATE_NAME = "registration";
  private static final String SPRING_LOGO_IMAGE = "templates/images/spring.png";
  private static final String PNG_MIME = "image/png";
  private static final String MAIL_SUBJECT = "Registration Confirmation";

  private final Environment environment;

  private final JavaMailSender mailSender;

  private final TemplateEngine htmlTemplateEngine;
  
  public UserController(Environment environment, JavaMailSender mailSender, TemplateEngine htmlTemplateEngine) {
    this.environment = environment;
    this.mailSender = mailSender;
    this.htmlTemplateEngine = htmlTemplateEngine;
  }
  
  @PostMapping("/register")
  public ResponseEntity<Object> register(@RequestBody User user)
      throws MessagingException, UnsupportedEncodingException {
    
    // TODO save user in the database here
    
    String confirmationUrl = "generated_confirmation_url";
    String mailFrom = environment.getProperty("spring.mail.properties.mail.smtp.from");
    String mailFromName = environment.getProperty("mail.from.name", "Identity");

    final MimeMessage mimeMessage = this.mailSender.createMimeMessage();
    final MimeMessageHelper email;
    email = new MimeMessageHelper(mimeMessage, true, "UTF-8");

    email.setTo(user.getEmail());
    email.setSubject(MAIL_SUBJECT);
    email.setFrom(new InternetAddress(mailFrom, mailFromName));

    final Context ctx = new Context(LocaleContextHolder.getLocale());
    ctx.setVariable("email", user.getEmail());
    ctx.setVariable("name", user.getName());
    ctx.setVariable("springLogo", SPRING_LOGO_IMAGE);
    ctx.setVariable("url", confirmationUrl);

    final String htmlContent = this.htmlTemplateEngine.process(TEMPLATE_NAME, ctx);

    email.setText(htmlContent, true);

    ClassPathResource clr = new ClassPathResource(SPRING_LOGO_IMAGE);

    email.addInline("springLogo", clr, PNG_MIME);

    mailSender.send(mimeMessage);

    Map<String, String> body = new HashMap<>();
    body.put("message", "User created successfully.");
    
    return new ResponseEntity<>(body, HttpStatus.OK);
  }
}

Test the application

Start the application and use an HTTP client to send a POST request to the URL http://localhost:8080/register.

Send a request to trigger the email sending.
Send a request to trigger the email sending.

We get the following output in the inbox.

Email received in the inbox that was sent from the Spring Boot application.
Email received in the inbox that was sent from the Spring Boot application.

It was the end of the tutorial when we saw how to send an email with Spring Boot and combine it with Thymeleaf to design a beautiful template.

Find the complete source code on the Github repository.

Follow me on Twitter or subscribe to my newsletter to avoid missing the upcoming posts and the tips and tricks I occasionally share.