How to Send Email From Spring Boot Applications

Spring framework provides a number of library classes for sending email. It provides an easy to use mail interface called JavaMailSender built on top of the JavaMail API. JavaMail API is a messaging framework available as part of Java SE and Java EE platforms.

Spring boot provides a starter project and auto configuration for JavaMailSender API. To use spring email features, just add the starter project spring-boot-starter-mail as a dependency on your project. Then configure the required spring.mail properties in the application.properties. With just these 2 steps, you can send email from spring boot applications.

The spring-boot-starter-mail adds the following dependent libraries to your project,

  • javax.mail
  • spring-context
  • spring-context-support
  • spring-boot-starter

Following are the configurable spring.mail properties,

  • spring.mail.host - Email server host
  • spring.mail.port - Email port
  • spring.mail.username - Email server username
  • spring.mail.password - Email server password
  • spring.mail.jndi-name - Session jndi name. If set overrides other properties
  • spring.mail.protocol - Protocol for email (smtp)
  • spring.mail.properties.* - JavaMail session properties

For a complete list of spring.mail.properties.* see this link. For example, the property spring.mail.properties.mail.smtp.timeout can be set to configure the socket read timeout.

Sending a Simple Text Email in Spring Boot Apps

Read this spring boot and sts tutorial first if you don't know how to create spring boot applications using spring tool suite. Note that all our sample projects use gradle build system (which is superior to maven).

Let us build a simple spring boot application which sends an email using a gmail account whenever a url is accessed. For simplicity, we will write the email functionality in the controller itself.

Step 1: Create a spring boot starter project with gradle support and web starter library. See this spring boot tutorial if you are not familiar with this step.

Step 2: Configure email properties in application.properties (src/main/resources).

spring.mail.host=smtp.gmail.com
spring.mail.port=587
spring.mail.username=username
spring.mail.password=password
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.connectiontimeout=5000
spring.mail.properties.mail.smtp.timeout=5000
spring.mail.properties.mail.smtp.writetimeout=5000

Step 3: Modify the build.gradle to add the spring-boot-starter-mail dependency.

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

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'

version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8

repositories {
    mavenCentral()
}

dependencies {
    compile('org.springframework.boot:spring-boot-starter-web')
    compile('org.springframework.boot:spring-boot-starter-mail')
    testCompile('org.springframework.boot:spring-boot-starter-test')
}

Step 4: Write a simple controller class and use JavaMailSender and MimeMessageHelper to send simple text email.

package com.quickprogrammingtips.springboot;

import javax.mail.internet.MimeMessage;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class SimpleEmailController {
    
    @Autowired
    private JavaMailSender sender;

    @RequestMapping("/simpleemail")
    @ResponseBody
    String home() {
        try {
            sendEmail();
            return "Email Sent!";
        }catch(Exception ex) {
            return "Error in sending email: "+ex;
        }
    }

    private void sendEmail() throws Exception{
        MimeMessage message = sender.createMimeMessage();
        MimeMessageHelper helper = new MimeMessageHelper(message);
        
        helper.setTo("set-your-recipient-email-here@gmail.com");
        helper.setText("How are you?");
        helper.setSubject("Hi");
        
        sender.send(message);
    }
}

Step 5: Since we are using gmail to send email, we need to enable "less secure access" on the gmail account. Log out from all the Google accounts from the browser. Login in to the gmail account configured in application.properties. Then click on this link and turn on access for less secure apps. In some cases, you may need to access this link as well! If you don't follow these steps, you will get the following error,

org.springframework.mail.MailAuthenticationException: Authentication failed; nested exception is javax.mail.AuthenticationFailedException: 534-5.7.14 Please log in via your web browser and 534-5.7.14 then try again.

Less secure sign in option is required for Yahoo mail as well. This article contains configuration details for other email providers such as Yahoo mail, sendgrid and mailgun.

Step 6: Access the URL http://localhost:8080/simpleemail to send email. Check the recipient email account to verify that email is working.

Sending Email Attachments in Spring Boot Apps

The following controller sends an email with a picture attached to it. We load a cat picture from the classpath. Before running this example, ensure that you have a cat.jpg file copied to the src/main/resources folder.

package com.quickprogrammingtips.springboot;

import javax.mail.internet.MimeMessage;

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.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class SimpleEmailController2 {
    
    @Autowired
    private JavaMailSender sender;

    @RequestMapping("/simpleemail2")
    @ResponseBody
    String home() {
        try {
            sendEmail();
            return "Email Sent!";
        }catch(Exception ex) {
            return "Error in sending email: "+ex;
        }
    }

    private void sendEmail() throws Exception{
        MimeMessage message = sender.createMimeMessage();
        
        // Enable the multipart flag!
        MimeMessageHelper helper = new MimeMessageHelper(message,true);
        
        helper.setTo("set-your-recipient-email-here@gmail.com");
        helper.setText("How are you?");
        helper.setSubject("Hi");
        
        ClassPathResource file = new ClassPathResource("cat.jpg");
        helper.addAttachment("cat.jpg", file);
        
        sender.send(message);
    }
}

Note that the above controller is configured on a different path(/simpleemail2). Also note the multipart flag passed as the second parameter to MimeMessageHelper constructor. If this is not set to true, you will get the following error,

java.lang.IllegalStateException: Not in multipart mode - create an appropriate MimeMessageHelper via a constructor that takes a 'multipart' flag if you need to set alternative texts or add inline elements or attachments.

Sending Email with Inline Resources in Spring Boot Apps

Before running this example, ensure that you have a cat.jpg file copied to the src/main/resources folder. The following controller embeds the cat picture to the email as an inline resource. The recipient will see the resource embedded in the email (not as an attachment). Note that resources must be added to the helper after adding the text.

package com.quickprogrammingtips.springboot;

import javax.mail.internet.MimeMessage;

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.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class SimpleEmailController3 {

    @Autowired
    private JavaMailSender sender;

    @RequestMapping("/simpleemail3")
    @ResponseBody
    String home() {
        try {
            sendEmail();
            return "Email Sent!";
        } catch (Exception ex) {
            return "Error in sending email: " + ex;
        }
    }

    private void sendEmail() throws Exception {
        MimeMessage message = sender.createMimeMessage();

        // Enable the multipart flag!
        MimeMessageHelper helper = new MimeMessageHelper(message, true);

        helper.setTo("set-your-recipient-email-here@gmail.com");
        helper.setText("<html><body>Here is a cat picture! <img src='cid:id101'/><body></html>", true);
        helper.setSubject("Hi");

        ClassPathResource file = new ClassPathResource("cat.jpg");
        helper.addInline("id101", file);

        sender.send(message);
    }
}

Sending Email with Velocity Templates in Spring Boot Apps

In any non trivial email application, it is important to use templates. This enables separation of the structure of an email from the actual data that is sent in each email. For example, you can create a welcome email template and then substitute just the name placeholder in the template to send personalized email to each user. The following example uses the popular velocity templating engine to send email.

Velocity is not an actively maintained project and hence as of spring 4.3 velocity engine is deprecated in favor of freemarker. We will ignore this warning in the following program. Also note that velocity auto configuration works only till spring boot 1.4.5.RELEASE. If you are using spring boot version 1.5.0.RELEASE or above and need auto configuration, you should switch to freemarker.

Let us first create a simple velocity template for welcome message in the folder src/main/resources with the name welcome.vm.

<html>
    <body>
        <h3>Hi ${user}, welcome to the application!</h3>
    </body>
</html>

Add spring-boot-starter-velocity to the build.gradle file and change the spring boot version to 1.4.5.RELEASE,

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

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'

version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8

repositories {
    mavenCentral()
}

dependencies {
    compile('org.springframework.boot:spring-boot-starter-web')
    compile('org.springframework.boot:spring-boot-starter-mail')
    compile('org.springframework.boot:spring-boot-starter-velocity')
    testCompile('org.springframework.boot:spring-boot-starter-test')
}

Finally let us create a controller to process velocity template and send the email,

package com.quickprogrammingtips.springboot;

import java.util.HashMap;
import java.util.Map;

import javax.mail.internet.MimeMessage;

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.stereotype.Controller;
import org.springframework.ui.velocity.VelocityEngineUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class SimpleEmailController4 {

    @Autowired
    private JavaMailSender sender;

    @Autowired
    private VelocityEngine velocityEngine;

    @RequestMapping("/simpleemail4")
    @ResponseBody
    String home() {
        try {
            sendEmail();
            return "Email Sent!";
        } catch (Exception ex) {
            return "Error in sending email: " + ex;
        }
    }

    private void sendEmail() throws Exception {
        MimeMessage message = sender.createMimeMessage();

        MimeMessageHelper helper = new MimeMessageHelper(message);

        Map<String, Object> model = new HashMap();
        model.put("user", "qpt");
        String text = VelocityEngineUtils.mergeTemplateIntoString(velocityEngine, "welcome.vm", model);

        helper.setTo("set-your-recipient-email-here@gmail.com");
        helper.setText(text, true); // set to html
        helper.setSubject("Hi");

        sender.send(message);
    }
}

Sending Email with FreeMarker Templates in Spring Boot Apps

Spring boot provides a starter project for using freemarker templates. Just add the spring-boot-starter-freemarker dependency to your project.

Let us start by creating a simple freemarker template named welcome.ftl in the src/main/resources folder,

<html>
    <body>
        <h3>Hi ${user}, welcome to the application!</h3>
    </body>
</html>

Modify the build.gradle to add a dependency on spring-boot-starter-freemarker. Note that we are using the latest version of spring boot (1.5.2.RELEASE),

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

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'

version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8

repositories {
    mavenCentral()
}

dependencies {
    compile('org.springframework.boot:spring-boot-starter-web')
    compile('org.springframework.boot:spring-boot-starter-mail')
    compile('org.springframework.boot:spring-boot-starter-freemarker')
 
    testCompile('org.springframework.boot:spring-boot-starter-test')
}

Finally create a controller to process freemarker template and send an email using JavaMailSender,

package com.quickprogrammingtips.springboot;

import java.util.HashMap;
import java.util.Map;

import javax.mail.internet.MimeMessage;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Controller;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import freemarker.template.Configuration;
import freemarker.template.Template;

@Controller
public class SimpleEmailController5 {

    @Autowired
    private JavaMailSender sender;

    @Autowired
    private Configuration freemarkerConfig;

    @RequestMapping("/simpleemail5")
    @ResponseBody
    String home() {
        try {
            sendEmail();
            return "Email Sent!";
        } catch (Exception ex) {
            return "Error in sending email: " + ex;
        }
    }

    private void sendEmail() throws Exception {
        MimeMessage message = sender.createMimeMessage();

        MimeMessageHelper helper = new MimeMessageHelper(message);

        Map<String, Object> model = new HashMap();
        model.put("user", "qpt");
        
        // set loading location to src/main/resources
        // You may want to use a subfolder such as /templates here
        freemarkerConfig.setClassForTemplateLoading(this.getClass(), "/");
        
        Template t = freemarkerConfig.getTemplate("welcome.ftl");
        String text = FreeMarkerTemplateUtils.processTemplateIntoString(t, model);

        helper.setTo("set-your-recipient-email-here@gmail.com");
        helper.setText(text, true); // set to html
        helper.setSubject("Hi");

        sender.send(message);
    }
}