Send Email Spring FreeMarker

Send Email Spring FreeMarker

In previous example you saw how to send email using Spring API without doing much coding. In this example I will show you how to use FreeMarker java template engine to create html template and send data in HTML format. You will be needed this functionality if you want to send email in HTML format.

Tools needed:

  • Eclipse any latest version
  • JDK 8
  • FreeMarker template jars
  • Log4j jars

To understand better I will create complete maven project and show you how initial set up can be done and finally will send sample email using this application. Create maven project name: SpringSendEmailFreeMarker as shown below and include all files and folders:

Send Email Spring FreeMarker

  • As first thing you need to do is include all dependencies in pom.xml:
<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.javahonk</groupId>
	<artifactId>SpringSendEmailFreeMarker</artifactId>
	<version>0.0.1-SNAPSHOT</version>

	<properties>
		<org.springframework.version>4.1.5.RELEASE</org.springframework.version>
		<org.apache.log4j.version>2.1</org.apache.log4j.version>
		<org.freemarker.version>2.3.20</org.freemarker.version>
		<javax.mail.version>1.4.6</javax.mail.version>		
	</properties>

	<dependencies>


		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${org.springframework.version}</version>
		</dependency>

		<!-- Various Application Context utilities, including EhCache, JavaMail, 
			Quartz, and Freemarker integration Define this if you need any of these integrations -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context-support</artifactId>
			<version>${org.springframework.version}</version>
		</dependency>

		<!-- Log4j -->
		<dependency>
			<groupId>org.apache.logging.log4j</groupId>
			<artifactId>log4j-api</artifactId>
			<version>${org.apache.log4j.version}</version>
		</dependency>

		<dependency>
			<groupId>org.apache.logging.log4j</groupId>
			<artifactId>log4j-core</artifactId>
			<version>${org.apache.log4j.version}</version>
		</dependency>

		<!-- mail components -->
		<dependency>
			<groupId>javax.mail</groupId>
			<artifactId>mail</artifactId>
			<version>${javax.mail.version}</version>
		</dependency>
		<dependency>
			<groupId>org.freemarker</groupId>
			<artifactId>freemarker</artifactId>
			<version>${org.freemarker.version}</version>
		</dependency>
		
	</dependencies>

</project>

Now include application configuration files inside src\main\resources folder:

  • spring-context.xml: Main file of the application as we are using Spring framework and here we keep all bean defintions, properties configuration load etc…
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
	xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:util="http://www.springframework.org/schema/util"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd
		http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.1.xsd
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd
		http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.1.xsd">

	<context:annotation-config />
	<context:component-scan base-package="com.javhaonk" />
	
	<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
		<property name="locations">
			<list>
				<value>javahonk.properties</value>								
			</list>
		</property>
		<property name="ignoreUnresolvablePlaceholders" value="true"/>
		<property name="ignoreResourceNotFound" value="true"/>
	</bean>
	
	<bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
    	<property name="host" value="${smtp.host}"/>
	</bean>

	<bean id="errorTemplate" class="org.springframework.mail.SimpleMailMessage">
	    <property name="from" value="${from_address}"/>
	    <property name="to" value="${to_address}"/>
	    <property name="subject" value="Message from error tempate: There is an error sending email"/>
	</bean> 
	
	<bean id="successTemplate" class="org.springframework.mail.SimpleMailMessage">
	    <property name="from" value="${from_address}"/>
	    <property name="to" value="${to_address}"/>
	    <property name="subject" value="${subject}"/>
	</bean> 
	
	<bean id="mailHelper" class="com.javahonk.report.util.MailHelper" />	
	
	<bean id="freemarkerConfiguration" class="freemarker.template.Configuration" />
	
	<bean id="simpleMailMessage" class="org.springframework.mail.SimpleMailMessage" />
	
	
	
</beans>
  • log4j2.xml: Used for application logging:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="INFO" shutdownHook="disable">

	<Properties>
		<Property name="envrionment.target">DEV</Property>
	</Properties>

	<Properties>
		<Property name="logging.dir">./</Property>
	</Properties>

	<Appenders>
		<Console name="Console" target="SYSTEM_OUT">
			<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
		</Console>

		<RollingFile name="RollingFile"
			fileName="logs/rolling-file.log"	filePattern="${sys:logging.dir}/logs/rolling-file-%d{yyyy-MM-dd}-%i.log">
			<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
			<!-- TODO:Change to time based policy -->
			<Policies>
				<TimeBasedTriggeringPolicy interval="1"	modulate="true" />
				<SizeBasedTriggeringPolicy size="100 MB" />
			</Policies>
			<DefaultRolloverStrategy max="4" />
		</RollingFile>
	</Appenders>

	<Loggers>
		<Root level="info">
			<AppenderRef ref="Console" />
			<!-- <AppenderRef ref="file" /> -->
			<AppenderRef ref="RollingFile" />
		</Root>
	</Loggers>
</Configuration>
  • JavaHonkFreeMarkerTemplate.ftl: FreeMarker template is which will be use to format and send eamil in HTML format:
<html>
<body>
  <h2>
    Java Honk: Send Email Using Spring and FreeMarker ${startDate} to ${endDate}
  </h2>

  <div>
  	<h3>
  	  Summary
  	</h3>
  	
  	<p>
  	Date processed : ${startDate}
  	<br/><br/>
  	Report from : ${startDate} to ${endDate}
  	</p>   
  
  </div>  
  
</body>
</html>
  • javahonk.properties: Central location to define application related properties and use through out the application:
smtp.host=localhost
from_address=From_javahonk@javahonk.com
to_address=To_javahonk@javahonk.com
subject=Send mail using Spring and FreeMarker template
  • MailHelper.java: This is main class which will be use to send email:
package com.javahonk.report.util;

import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.mail.internet.MimeMessage;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.MailException;
import org.springframework.mail.MailSender;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.mail.javamail.MimeMessagePreparator;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;

import freemarker.cache.FileTemplateLoader;
import freemarker.template.Configuration;

public class MailHelper {
	
	private static final Logger logger = LogManager.getLogger(MailHelper.class.getName());
	
	@Autowired
	private MailSender mailSender;
	
	@Autowired
	@Qualifier("mailSender")
	private JavaMailSender javaMailSender;
	
	@Autowired
	Configuration freemarkerConfiguration;
	
	@Value("${from_address}")
	private String fromAddress;
	
	@Value("${subject}")
	private String subject;
	
	public void sendTemplatedMimeMessage(
			final Map<String, Object> templatedMimeMessage,
			final String template,
			final List<String> toAddresses,
			final Map<String, File> attachments) throws IOException{
		
		FileTemplateLoader templateLoader = null;
		templateLoader = new FileTemplateLoader(new File("src/main/resources"));
		freemarkerConfiguration.setTemplateLoader(templateLoader);		
		
		MimeMessagePreparator preparator;
		try {
			preparator = new MimeMessagePreparator() {
				
				String messageText = 
						FreeMarkerTemplateUtils.processTemplateIntoString(
								freemarkerConfiguration.getTemplate(template),templatedMimeMessage);
				
				@Override
				public void prepare(MimeMessage message) throws Exception {
					
					MimeMessageHelper helper = new MimeMessageHelper(message, true);
					
					for(String address : toAddresses){
						helper.addTo(address);
					}
					
					helper.setFrom(fromAddress);
					helper.setSubject(subject);
					
					if(attachments!=null){
						
						for(Entry<String, File> attachment : attachments.entrySet()){
							
							helper.addAttachment(attachment.getKey(), attachment.getValue());
						}
						
					}
					
					helper.setText(messageText,true);
				}
			};
			
			this.javaMailSender.send(preparator);
			
		} catch (Exception ex) {
			
			logger.error("Failed to send email for templated message:" +
					"\nFrom:" + fromAddress +
					"\nTo:" + toAddresses +
					"\nMessageMap:" + templatedMimeMessage, ex);
			
		} 
		
	}
	
	public void sendMimeMessage(
			final String mimeMessage,
			final String fromAddress,
			final List<String> toAddresses,
			final String mailSubject,
			final Map<String, File> attachments){
		
		MimeMessagePreparator preparator = new MimeMessagePreparator() {
			
			@Override
			public void prepare(MimeMessage message) throws Exception {
				
				MimeMessageHelper helper = new MimeMessageHelper(message, true);
				
				for(String address : toAddresses){
					helper.addTo(address);
				}
				
				helper.setFrom(fromAddress);
				helper.setSubject(mailSubject);
				
				if(attachments!=null){
					
					for(Entry<String, File> attachment : attachments.entrySet()){
						
						helper.addAttachment(attachment.getKey(), attachment.getValue());
					}
					
				}
				
				helper.setText(mimeMessage);
			}
		};
		
		try{
			
            this.javaMailSender.send(preparator);
            
        }
        catch (MailException ex) {
        	
        	logger.error("Failed to send email for templated message:" +
					"\nFrom:" + fromAddress +
					"\nTo:" + toAddresses +
					"\nMessage:" + mimeMessage, ex);
        }
		
	}

	public void sendSimpleMailMessage(
			SimpleMailMessage templateMessage,
			String message){
		
		SimpleMailMessage msg = new SimpleMailMessage(templateMessage);
		
		msg.setText(message);
		
		try{
			
            this.mailSender.send(msg);
            
        }
        catch (MailException ex) {
        	
			logger.error("Failed to send email for templated message:" +
					"\nFrom:" + templateMessage.getFrom() +
					"\nTo:" + templateMessage.getTo() +
					"\nMessage:" + templateMessage.getText(), ex);

        }
		
	}
	
}
  • SendEmailUsingFreeMarker.java: Java main class to load application and send emails:
package com.javahonk.report;

import java.io.File;
import java.io.IOException;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.mail.SimpleMailMessage;

import com.javahonk.report.util.MailHelper;

public class SendEmailUsingFreeMarker {
	
	private static final Logger logger = LogManager.getLogger(SendEmailUsingFreeMarker.class);

	public static void main(String[] args) throws BeansException, IOException {
		
		logger.info("Application is starting");
		
		ApplicationContext context = new ClassPathXmlApplicationContext("spring-context.xml");
		
		SimpleMailMessage successTemplate = (SimpleMailMessage)context.getBean("successTemplate");
		
		SimpleMailMessage errorTemplate = (SimpleMailMessage)context.getBean("errorTemplate");
		
		Map<String, File> attachments = new HashMap<String, File>();
		attachments.put("JavaHonk.xlsx", new File("JavaHonk.xlsx"));
		
		List<String> toAddress = new ArrayList<String>();
		toAddress.add("To_javahonk@javahonk.com");	
		
		//Send message using Free Marker template
		Map<String, Object> freeMarkderTemplateMap = new HashMap<String, Object>();
		
		freeMarkderTemplateMap.put("startDate", LocalDate.now());
		freeMarkderTemplateMap.put("endDate", LocalDate.now());
		
		List<String> toAddressList = new ArrayList<String>();
		toAddressList.add("To_JavaHOnk@JavaHonk.com");
		
		context.getBean(MailHelper.class).sendTemplatedMimeMessage(freeMarkderTemplateMap, "JavaHonkFreeMarkerTemplate.ftl", toAddressList, attachments);
		
		//Send mail with attachment
		context.getBean(MailHelper.class).sendMimeMessage(
				"Message: Reponse sent successfully",
				"From_javahonk@javahonk.com", toAddress,
				"Subject: Send email using Spring framework", attachments);
		
		//Simple message configure in spring context file
		context.getBean(MailHelper.class).sendSimpleMailMessage(successTemplate, "Java Honk Test Message");
		
		//Error template to send message in case or error
		context.getBean(MailHelper.class).sendSimpleMailMessage(errorTemplate, "Java Honk Error Message");
		
		((AbstractApplicationContext) context).close();

	}

}
  • That’s it. If you have SMTP server setup you could change it in javahonk.properties file for smtp.host=localhost and if you don’t have any SMTP server for test please download and use FakeSMTP from here as I will also use this FakeSMTP server to send an email. To run just start FakeSmtp server then run SendEmailUsingFreeMarker as java application. If all setup done correctly you should see below emails in FakeSMTP server as below:

Send Email Spring FreeMarker

  • All the email are accessible for this example we have to verify if FreeMarker template generated email or not. Open first email you will see below email formatted by FreeMarker:

Send Email Spring FreeMarker

download Download Project: SpringSendEmailFreeMarker

Leave a Reply

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