Spring Mail – Sending Email with Freemarker HTML Template Example
In this tutorial we demonstrate how to send a HTML email using a custom freemarker template using spring framework. In this topic we learn how to create and configure a custom freemarker template using spring.
Project Structure
Let’s start by looking at our project structure.
Maven Dependencies
We use Apache Maven to manage our project dependencies. Make sure the following dependencies reside on your class-path.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.memorynotfound.mail</groupId>
<artifactId>mail-template-freemaker</artifactId>
<version>1.0.0-SNAPSHOT</version>
<url>https://memorynotfound.com</url>
<name>Spring MAIL - ${project.artifactId}</name>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.7.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
Email Configuration Properties
We can use two types of configuration files. Both files reside on the classpath located in the src/main/resources
folder. The first and my favorite is application.yml
file. I like this type because it has a better structure than the other and you’ll have to type less.
# application.yml
spring:
mail:
default-encoding: UTF-8
host: smtp.gmail.com
username: [email protected]
password: secret
port: 587
properties:
mail:
smtp:
auth: true
starttls:
enable: true
protocol: smtp
test-connection: false
The second option you can use is the application.properties
file.
# application.properties
spring.mail.default-encoding=UTF-8
spring.mail.host=smtp.gmail.com
[email protected]
spring.mail.password=secret
spring.mail.port=587
spring.mail.protocol=smtp
spring.mail.test-connection=false
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true
Mail Object
We are using this Mail
object to pass as an argument for our EmailService
to encapsulate the details of an email message and content.
package com.memorynotfound.mail;
public class Mail {
private String from;
private String to;
private String subject;
private String content;
public Mail() {
}
public Mail(String from, String to, String subject, String content) {
this.from = from;
this.to = to;
this.subject = subject;
this.content = content;
}
public String getFrom() {
return from;
}
public void setFrom(String from) {
this.from = from;
}
public String getTo() {
return to;
}
public void setTo(String to) {
this.to = to;
}
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
@Override
public String toString() {
return "Mail{" +
"from='" + from + '\'' +
", to='" + to + '\'' +
", subject='" + subject + '\'' +
", content='" + content + '\'' +
'}';
}
}
Freemarker Template Java Configuration
We need to tell freemarker
where the email templates are located. We do this by creating a FreeMarkerConfigurationFactoryBean
and set the location using the setTemplateLoaderPath()
method. This tells freemarker to look for a folder on the class-path named templates.
package com.memorynotfound.mail;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.ui.freemarker.FreeMarkerConfigurationFactoryBean;
@Configuration
public class FreemarkerConfig {
@Bean
public FreeMarkerConfigurationFactoryBean getFreeMarkerConfiguration() {
FreeMarkerConfigurationFactoryBean bean = new FreeMarkerConfigurationFactoryBean();
bean.setTemplateLoaderPath("/templates/");
return bean;
}
}
Freemarker HTML Email Template
Now it’s time to write the actual freemarker HTML email template. This file is located in the src/main/resources/templates
folder. We create a very basic HTML email template. Notice, we are linking to an email attachment by using the cid:
inside the src
attribute inside the <img/>
element. This image will be attached as an attachment in the email service.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Sending Email with Freemarker HTML Template Example</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<link href='http://fonts.googleapis.com/css?family=Roboto' rel='stylesheet' type='text/css'>
<!-- use the font -->
<style>
body {
font-family: 'Roboto', sans-serif;
font-size: 48px;
}
</style>
</head>
<body style="margin: 0; padding: 0;">
<table align="center" border="0" cellpadding="0" cellspacing="0" width="600" style="border-collapse: collapse;">
<tr>
<td align="center" bgcolor="#78ab46" style="padding: 40px 0 30px 0;">
<img src="cid:logo.png" alt="https://memorynotfound.com" style="display: block;" />
</td>
</tr>
<tr>
<td bgcolor="#eaeaea" style="padding: 40px 30px 40px 30px;">
<p>Dear ${name},</p>
<p>Sending Email using Spring Boot with <b>FreeMarker template !!!</b></p>
<p>Thanks</p>
</td>
</tr>
<tr>
<td bgcolor="#777777" style="padding: 30px 30px 30px 30px;">
<p>${signature}</p>
<p>${location}</p>
</td>
</tr>
</table>
</body>
</html>
Populating HTML Email with Freemarker Template
First, we can create a MimeMessage
using the JavaMailSender.createMimeMessage()
method. Next, we create a MimeMessageHelper
and pass in the MimeMessage
as an argument. The MimeMessageHelper
let’s us add attachments to the MimeMessage
.
Then, we lookup the freemarker template using the Configuration.getTemplate()
method. Finally, we process the template using the FreeMarkerTemplateUtils.processTemplateIntoString()
method and pass in the template and a model. This model are key values which can be used inside the freemarker template.
package com.memorynotfound.mail;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
@Service
public class EmailService {
@Autowired
private JavaMailSender emailSender;
@Autowired
private Configuration freemarkerConfig;
public void sendSimpleMessage(Mail mail) throws MessagingException, IOException, TemplateException {
MimeMessage message = emailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message,
MimeMessageHelper.MULTIPART_MODE_MIXED_RELATED,
StandardCharsets.UTF_8.name());
helper.addAttachment("logo.png", new ClassPathResource("memorynotfound-logo.png"));
Template t = freemarkerConfig.getTemplate("email-template.ftl");
String html = FreeMarkerTemplateUtils.processTemplateIntoString(t, mail.getModel());
helper.setTo(mail.getTo());
helper.setText(html, true);
helper.setSubject(mail.getSubject());
helper.setFrom(mail.getFrom());
emailSender.send(message);
}
}
Spring Mail – Sending Email with Freemarker HTML Template Example
We are using Spring Boot to bootstrap our application. When the application is invoked we simply create a new Mail
object and send it using our previously created EmailService
package com.memorynotfound.mail;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import java.util.HashMap;
import java.util.Map;
@SpringBootApplication
public class Application implements ApplicationRunner {
private static Logger log = LoggerFactory.getLogger(Application.class);
@Autowired
private EmailService emailService;
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
@Override
public void run(ApplicationArguments applicationArguments) throws Exception {
log.info("Sending Email with Freemarker HTML Template Example");
Mail mail = new Mail();
mail.setFrom("[email protected]");
mail.setTo("[email protected]");
mail.setSubject("Sending Email with Freemarker HTML Template Example");
Map model = new HashMap();
model.put("name", "Memorynotfound.com");
model.put("location", "Belgium");
model.put("signature", "https://memorynotfound.com");
mail.setModel(model);
emailService.sendSimpleMessage(mail);
}
}
Example Received Email
If your configuration is correct, you should receive the following email in your inbox.
References
- Spring Integration – Sending Emails Documentation
- Spring Boot – Sending Emails Documentation
- Freemarker Official Website
- Spring Boot – Common Application Properties
- JavaMailSender JavaDoc
- MimeMessage JavaDoc
- MimeMessageHelper JavaDoc
- FreeMarkerConfigurationFactoryBean JavaDoc
Thank you, this was very helpful!
I noticed your example code didn’t work out of the box for me, but after two small adjustments it was fine:
EmailService.java
, we had to usehelper.addInline("logo.png", new ClassPathResource("memorynotfound-logo.png"));
instead of addAttachment.setText
call, instead of before it.After this, we got emails coming out with attachments shown inline just as in your example.
This guide could be improved. If using
helper.addInline
versushelper.addAttachment
make sure to callhelper.setText
before any calls toaddInline
otherwise the image will not be properly added.mail.getModel() is not defined
mail.setModel() is not defined too
Map model = new HashMap();
model.put(“name”, “Memorynotfound.com”);
model.put(“location”, “Belgium”);
model.put(“signature”, “https://memorynotfound.com”);
I got error : “javax.mail.AuthenticationFailedException: 454 4.7.0 Too many login attempts, please try again later…”
What should I do? :((
You probably been rate-limited by google. Wait a little while, and try again. You’ve probably used the wrong user/password combination?
Hi! Seems to be a nice way to load html files. I’m facing a little problem, though. It seems like none of my ftl files are being cached. At one point, after failing to retrieve the ftl file from cache, the code goes and searches for a _.ftl, but even with a file corresponding that name in the correct folder it doesn’t work. Inside the Configuration#createTemplateCache() method, the loader points to the correct templateLoaderPath set on the FreemarkerConfig. One question, is the folder hierarchy correct in this example? Because mine is exactly the same, even the folder’s name. Error: java.io.FileNotFoundException:… Read more »
Hi, I am not getting Image in Mail content, Attachment are working,
Please see attached Image