Send email using email template library via Spring

This tutorial will show you how to send a basic mail via Spring framework’s email support using Velocity email template library. We will use class org.springframework.mail.javamail.MimeMessageHelper, which shields you from having to use the verbose JavaMail API. Using the MimeMessageHelper it is pretty easy to create a MimeMessage.

The code in the other email sending examples explicitly created the content of the email message, using methods calls such as message.setText(..). This is fine for simple cases, and it is okay in the context of the aforementioned examples, where the intent was to show you the very basics of the API.

In typical enterprise application though, you are not going to create the content of your emails using the above approach for a number of reasons.

  • Creating HTML-based email content in Java code is tedious and error prone
  • There is no clear separation between display logic and business logic
  • Changing the display structure of the email content requires writing Java code, recompiling, redeploying…

Typically the approach taken to address these issues is to use a template library such as FreeMarker or Velocity to define the display structure of email content. This leaves your code tasked only with creating the data that is to be rendered in the email template and sending the email.

It is definitely a best practice for when the content of your emails becomes even moderately complex, and with the Spring Framework’s support classes for FreeMarker and Velocity becomes quite easy to do. Find below an example of using the Velocity template library to create email content.

To use Velocity to create your email template(s), you will need to have the Velocity libraries available on your classpath. You will also need to create one or more Velocity templates for the email content that your application needs.

The following example shows you how to use the MimeMessageHelper to send an email using Velocity Engine.

Prerequisites

Eclipse 2019-12, Java at least 1.8, Gradle 6.4.1, Maven 3.6.3, Spring Boot Mail Starter 2.3.1, Java mail API 1.6.2

Project Setup

Create either gradle or maven based project in Eclipse. The name of the project is spring-email-using-template-library.

If you are creating gradle based project then you can use below build.gradle script:

buildscript {
	ext {
		springBootVersion = '2.3.1.RELEASE'
	}
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
    }
}

plugins {
    id 'java-library'
    id 'org.springframework.boot' version "${springBootVersion}"
}

sourceCompatibility = 12
targetCompatibility = 12

repositories {
    mavenCentral()
}

dependencies {
	implementation("org.springframework.boot:spring-boot-starter-mail:${springBootVersion}")
	implementation('org.springframework.boot:spring-boot-starter-velocity:1.4.7.RELEASE')
	implementation('javax.mail:javax.mail-api:1.6.2')
}

If you are creating maven based project then you can use below pom.xml file:

If you are creating maven based project then you can use below pom.xml file:

<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.roytuts</groupId>
	<artifactId>spring-email-inline-attachment</artifactId>
	<version>0.0.1-SNAPSHOT</version>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.3.1.RELEASE</version>
	</parent>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-mail</artifactId>
		</dependency>
		
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-velocity</artifactId>
			<version>1.4.7.RELEASE</version>
		</dependency>
		
		<dependency>
			<groupId>javax.mail</groupId>
			<artifactId>javax.mail-api</artifactId>
			<version>1.6.2</version>
		</dependency>
	</dependencies>

    <build>
        <plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.8.1</version>
				<configuration>
					<source>at least 8</source>
					<target>at least 8</target>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>

Email Configuration

We will create an email configuration class where we will configure SMTP (Simple Mail Transfer Protocol) server details, from email address.

As we are using Velocity engine as an email template library, so we are defining bean for Velocity as well.

package com.roytuts.spring.email.using.template.library;

import java.util.Properties;

import org.apache.velocity.app.VelocityEngine;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.JavaMailSenderImpl;

@Configuration
public class EmailConfig {

	@Bean
	public JavaMailSender mailSender() {
		JavaMailSenderImpl mailSender = new JavaMailSenderImpl();

		mailSender.setHost("smtp.gmail.com");
		mailSender.setPort(587);
		mailSender.setUsername("gmail@gmail.com");
		mailSender.setPassword("gmail password");

		Properties javaMailProperties = new Properties();
		javaMailProperties.put("mail.smtp.auth", true);
		javaMailProperties.put("mail.smtp.starttls.enable", true);

		mailSender.setJavaMailProperties(javaMailProperties);

		return mailSender;
	}

	@Bean
	public VelocityEngine velocityEngine() {
		VelocityEngine engine = new VelocityEngine();

		engine.setProperty("resource.loader", "class");
		engine.setProperty("class.resource.loader.class",
				"org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");

		return engine;
	}

}

We need to issue STARTTLS command otherwise you will get the error message similar to the following:

#smtplib.SMTPSenderRefused: (530, b'5.7.0 Must issue a STARTTLS command first. p7sm24605501pfn.14 - gsmtp', 'gmailaddress@gmail.com')

You will get below error if your security level is high:

#smtplib.SMTPAuthenticationError: (535, b'5.7.8 Username and Password not accepted. Learn more at\n5.7.8  https://support.google.com/mail/?p=BadCredentials x10sm26098036pfn.36 - gsmtp')

Therefore you need to lower your Gmail’s security settings.

Email Sender

Email sender class just does the right job for sending the email to the intended recipient.

We are using email template to send the message. The template file is kept under src/main/resources/velocity folder.

package com.roytuts.spring.email.using.template.library;

import java.io.StringWriter;

import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.mail.javamail.MimeMessagePreparator;
import org.springframework.stereotype.Component;

@Component
public class EmailSender {

	@Autowired
	private JavaMailSender mailSender;

	@Autowired
	private VelocityEngine velocityEngine;

	public void sendEmailUsingVelocityTemplate(final String subject, final String message,
			final String fromEmailAddress, final String toEmailAddress, User user) {

		MimeMessagePreparator preparator = new MimeMessagePreparator() {
			public void prepare(MimeMessage mimeMessage) throws Exception {
				MimeMessageHelper message = new MimeMessageHelper(mimeMessage);
				message.setTo(toEmailAddress);
				message.setFrom(new InternetAddress(fromEmailAddress));

				VelocityContext velocityContext = new VelocityContext();
				velocityContext.put("user", user);

				StringWriter stringWriter = new StringWriter();

				velocityEngine.mergeTemplate("velocity/email-template.vm", "UTF-8", velocityContext, stringWriter);

				message.setSubject(subject);
				message.setText(stringWriter.toString(), true);
			}
		};

		try {
			mailSender.send(preparator);

			System.out.println("Email sending complete.");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}

Email Template

Create email template file called email-template.vm under src/main/resources/velocity folder.

<html>
    <body>
        <h3>Hello ${user.userName}, welcome to the Velocity Email Template!</h3>
        <div>
            Your email address is <a href="mailto:${user.emailAddress}">${user.emailAddress}</a>.
        </div>
    </body>
</html>

DTO Class

We create a simple POJO class that will be used as an object which is set on VelocityContext.

package com.roytuts.spring.email.using.template.library;

public class User {

	private String userName;
	private String emailAddress;

	public User(String userName, String emailAddress) {
		this.userName = userName;
		this.emailAddress = emailAddress;
	}

	//getters and setters
}

Main Class

A class is having main method with @SpringBootApplication annotation is enough to start up the Spring Boot application.

In this class we specify the subject, message, user information and the recipient to send the email.

package com.roytuts.spring.email.using.template.library;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class VelocityEmailTemplateLibraryApp implements CommandLineRunner {

	@Autowired
	private EmailSender emailSender;

	public static void main(String[] args) {
		SpringApplication.run(VelocityEmailTemplateLibraryApp.class, args);
	}

	@Override
	public void run(String... args) throws Exception {
		emailSender.sendEmailUsingVelocityTemplate("Email using Velocity Template Library",
				"Email Message using MimeMessagePreparator and Velocity Template Library", "gmail@gmail.com",
				"gmail@gmail.com", new User("John", "john@email.com"));
	}

}

Testing the Application

Now executing the main class will send the email to the intended recipient and you will see the below output in console:

Email sending complete.

Check the inbox you will get a message. If you do not find the message in inbox then check the Spam folder.

I have sent email to myself, so I am seeing me as a from email address.

Email in inbox:

email using velocity template library in spring

Email details:

email using velocity template library in spring

Source Code

Download

Thanks for reading.

Leave a Reply

Your email address will not be published. Required fields are marked *