Sending Emails using Spring JavaMailSender

Spring send email program for explaing the usage of javamailsender interface of javax.mail dependency. Send email example in Java using Spring framework.

email subscription

Learn to send emails in Spring provided JavaMailSender interface. Here is a step-by-step example of sending emails via Gmail SMTP server. We will use javax.mail maven dependency to send emails while configuring mail properties in JavaMailSenderImpl class that implements JavaMailSender interface.

1. Maven

Follow maven project creation example for creating a new project. Now import Spring dependencies along with javax.mail.

<properties>
  <spring.version>5.3.23</spring.version>
  <email.version>1.6.2</email.version>
</properties>
 
<!-- Spring Context Support -->
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-context-support</artifactId>
  <version>${spring.version}</version>
</dependency>
 
<dependency>
  <groupId>com.sun.mail</groupId>
  <artifactId>javax.mail</artifactId>
  <version>${email.version}</version>
</dependency>

If we are using Spring boot, then we can help of its autoconfiguration feature by simply including the spring-boot-starter-mail starter.

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-mail</artifactId>
</dependency>

The starter template will transitively import the required jars in the project.

[INFO] \- org.springframework.boot:spring-boot-starter-mail:jar:2.1.2.RELEASE:compile
[INFO]    +- org.springframework:spring-context-support:jar:5.1.4.RELEASE:compile
[INFO]    |  \- org.springframework:spring-beans:jar:5.1.4.RELEASE:compile
[INFO]    \- com.sun.mail:javax.mail:jar:1.6.2:compile
[INFO]       \- javax.activation:activation:jar:1.1:compile

2. Sending a SimpleMailMessage using JavaMailSender

2.1. Configuring JavaMailSenderImpl and Email Template

Given is Java configuration for JavaMailSender which has been configured to use Gmail SMTP settings and we have configured a sample email template preconfigured with sender/receiver emails and email text.

We can further customize the configuration as per our needs.

import java.util.Properties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.JavaMailSenderImpl;

@Configuration
public class EmailConfig
{
	@Bean
	public JavaMailSender getJavaMailSender()
	{
	    JavaMailSender mailSender = new JavaMailSenderImpl();
	    mailSender.setHost("smtp.gmail.com");
	    mailSender.setPort(25);

	    mailSender.setUsername("admin@gmail.com");
	    mailSender.setPassword("password");

	    Properties props = mailSender.getJavaMailProperties();
	    props.put("mail.transport.protocol", "smtp");
	    props.put("mail.smtp.auth", "true");
	    props.put("mail.smtp.starttls.enable", "true");
	    props.put("mail.debug", "true");

	    return mailSender;
	}

	@Bean
	public SimpleMailMessage emailTemplate()
	{
		SimpleMailMessage message = new SimpleMailMessage();
		message.setTo("somebody@gmail.com");
		message.setFrom("admin@gmail.com");
	    message.setText("FATAL - Application crash. Save your job !!");
	    return message;
	}
}

2.2. Sending Email

The EmailService class uses the beans configured in applicationContext.xml file and uses them to send messages.

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.stereotype.Service;

@Service("emailService")
public class EmailService
{
    @Autowired
    private JavaMailSender mailSender;

    @Autowired
    private SimpleMailMessage preConfiguredMessage;

    /**
     * This method will send compose and send a new message
     * */
    public void sendNewMail(String to, String subject, String body)
    {
        SimpleMailMessage message = new SimpleMailMessage();
        message.setTo(to);
        message.setSubject(subject);
        message.setText(body);
        mailSender.send(message);
    }

    /**
     * This method will send a pre-configured message
     * */
    public void sendPreConfiguredMail(String message)
    {
        SimpleMailMessage mailMessage = new SimpleMailMessage(preConfiguredMessage);
        mailMessage.setText(message);
        mailSender.send(mailMessage);
    }
}

3. Using JavaMailSender and MimeMessagePreparator

The recommended way of using JavaMailSender interface is the MimeMessagePreparator mechanism and using a MimeMessageHelper for populating the message.

@Autowired
private JavaMailSender mailSender;

public void sendMail() {  

	MimeMessagePreparator messagePreparator = new MimeMessagePreparator() {  
		public void prepare(MimeMessage mimeMessage) throws Exception {  
			MimeMessageHelper message = new MimeMessageHelper(mimeMessage, true, "UTF-8");
			message.setFrom("me@mail.com");
			message.setTo("you@mail.com");
			message.setSubject("Mail subject");
			message.setText("some text <img src='cid:logo'>", true);
			message.addInline("logo", new ClassPathResource("img/logo.gif"));
			message.addAttachment("myDocument.pdf", new ClassPathResource("uploads/document.pdf"));
		}  
	};  

	mailSender.send(messagePreparator);  
}

4. Mail Properties

We can configure the mail properties into application.properties file and inject using the @Value annotation.

spring.mail.host=smtp.gmail.com
spring.mail.port=25
spring.mail.username=admin@gmail.com
spring.mail.password=password

spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.transport.protocol=smtp
spring.mail.properties.mail.smtp.starttls.enable=true

#Timeouts
spring.mail.properties.mail.smtp.connectiontimeout=5000
spring.mail.properties.mail.smtp.timeout=5000
spring.mail.properties.mail.smtp.writetimeout=5000

If you are planning to use Amazon SES for sending emails, then you can use the following properties:

spring.mail.host=email-smtp.us-west-2.amazonaws.com
spring.mail.username=username
spring.mail.password=password

spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.transport.protocol=smtp
spring.mail.properties.mail.smtp.port=25
spring.mail.properties.mail.smtp.starttls.enable=true
spring.mail.properties.mail.smtp.starttls.required=true

5. Email Attachments and Inline Resources

It is easy to send simple mail messages containing only HTML, with no attachments or inline elements. However, inline elements and attachments are still a major compatibility issue between email clients.

Please use the appropriate MULTIPART_MODE and test the code thoroughly before pushing the code into production.

5.1. Email Attachments

To attach a file with email, use MimeMessageHelper to attach the file with a MimeMessage.

public void sendMailWithAttachment(String to, String subject, String body, String fileToAttach)
{
    MimeMessagePreparator preparator = new MimeMessagePreparator()
    {
        public void prepare(MimeMessage mimeMessage) throws Exception
        {
            mimeMessage.setRecipient(Message.RecipientType.TO, new InternetAddress(to));
            mimeMessage.setFrom(new InternetAddress("admin@gmail.com"));
            mimeMessage.setSubject(subject);
            mimeMessage.setText(body);

            FileSystemResource file = new FileSystemResource(new File(fileToAttach));
            MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
            helper.addAttachment("logo.jpg", file);
        }
    };

    try {
        mailSender.send(preparator);
    }
    catch (MailException ex) {
        // simply log it and go on...
        System.err.println(ex.getMessage());
    }
}

5.2. Inline Resources

Sometimes, we may want to attach inline resources such as inline images in email body. Inline resources are added to the MimeMessage by using the specified Content ID. Be sure first to add the text and then the resources. If you are doing it the other way around, it does not work.

public void sendMailWithInlineResources(String to, String subject, String fileToAttach) 
{
    MimeMessagePreparator preparator = new MimeMessagePreparator() 
    {
        public void prepare(MimeMessage mimeMessage) throws Exception 
        {
            mimeMessage.setRecipient(Message.RecipientType.TO, new InternetAddress(to));
            mimeMessage.setFrom(new InternetAddress("admin@gmail.com"));
            mimeMessage.setSubject(subject);
             
            MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
             
            helper.setText("<html><body><img src='cid:identifier1234'></body></html>", true);
             
            FileSystemResource res = new FileSystemResource(new File(fileToAttach));
            helper.addInline("identifier1234", res);
        }
    };
     
    try {
        mailSender.send(preparator);
    }
    catch (MailException ex) {
        // simply log it and go on...
        System.err.println(ex.getMessage());
    }
}

6. Demo

Time to test the spring mail sender program code. I am sending two messages from the test code. One is instantiated and composed in the test class itself, and the other is a pre-configured message from applicationContext.xml file.

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

public class SpringEmailTest
{
	public static void main(String[] args)
    {
        //Create the application context
        ApplicationContext context = new FileSystemXmlApplicationContext
        			("classpath:com/howtodoinjava/core/email/applicationContext.xml");

        //Get the mailer instance
        EmailService mailer = (EmailService) context.getBean("emailService");

        //Send a composed mail
        mailer.sendMail("somebody@gmail.com", "Test Subject", "Testing body");

        //Send a pre-configured mail
        mailer.sendPreConfiguredMail("Exception occurred everywhere.. where are you ????");
    }
}

The above call will send the emails.

Happy Learning !!

Leave a Comment

  1. Hi, I also wrote an application to send emails using templates and custom data. For this, I used Thymeleaf and Template engine to bind dynamic data and email template. Now, I’ve to run a loop for all the users and perform binding the data and template and send the email. Is there anyway all the emails can be fired at once with dynamic data binded to them?

    Reply
  2. Hi Lokesh,
    like i have 5 smtp server’s and i want to do bulk mailing and want to post on each server then how i can achieve it ?

    Reply
    • I am using like this now :
      String smtpHost=”smtp.gmail.com”;
      javaMailSender.setHost(smtpHost);
      Properties mailProps = new Properties();
      mailProps.put(“mail.smtp.connectiontimeout”, “2000”);
      mailProps.put(“mail.smtp.timeout”, “2000”);
      mailProps.put(“mail.debug”, “false”);
      javaMailSender.setJavaMailProperties(mailProps);

      Now i want to post on multiple VIP’s like
      String smtpHost=”192.168.xx.xx,192.168.xx.xx,192.168.xx.xx”;

      Can you suggest how i can achieve this ?

      Reply
  3. Hi,
    how i can generate oauth2 access token to send mail using smtp gmail server. Above code is works when i set my account less secure app .

    thanks in advance

    Reply
  4. Hi Lokesh,

    I am using Spring mail API, Thank you for providing this tutorial. Its very helpful.
    I am facing one issue.

    If I am send an email to an incorrect email id which does not exists, I am not getting any exceptions.

    Could you please provide me any suggestions, like how to track mail sending failed due to email address issues or some other issues?

    My Email ID is: xxxxxxxx@gmail.com

    Thanks & Regards,
    Kishore.

    Reply
    • Most SMTP servers do not respond back to clients incase the email fails to send. Rather they send a new “Email delivery failed” message back to the sender. If the server is not returning the failure status, then it is almost impossible to report such errors on the client side.

      Reply
  5. Hi Lokesh,
    I am getting the following exception even when the user name password are correct :-
    Exception in thread “main” org.springframework.mail.MailAuthenticationException: Authentication failed; nested exception is javax.mail.AuthenticationFailedException: 534-5.7.14

    After getting this exception I got an email from google with subject Google Account: sign-in attempt blocked and asked me to change setting to use less secure setting so that your account is no longer protected by modern security standards. I made the gmail settings changed to less secure and now the code runs fine.

    Is there any way to make the gmail setting secured and at the same time sending mail via spring ??
    Please suggest.

    Reply
  6. Nice explanation Lokesh,
    I have also used same implementation for sending mail and it is running successfully.
    There is one issue i faced is that, as I am sending some critical data in mail and it gets logged in console.
    So is there any way to disable logger for not logging critical mail content or whole mail content ?
    Thanks in advance

    Reply
  7. Hi, I keep having the same error. When I try to send the mail, I’m getting the following error:

    org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.mail.MailSendException: Mail server connection failed; nested exception is com.sun.mail.util.MailConnectException: Couldn’t connect to host, port: smtp.gmail.com, 25; timeout -1;
    nested exception is:
    java.net.ConnectException: Connection timed out: connect. Failed messages: com.sun.mail.util.MailConnectException: Couldn’t connect to host, port: smtp.gmail.com, 25; timeout -1;
    nested exception is:
    java.net.ConnectException: Connection timed out: connect; message exceptions (1) are:
    Failed message 1: com.sun.mail.util.MailConnectException: Couldn’t connect to host, port: smtp.gmail.com, 25; timeout -1;
    nested exception is:
    java.net.ConnectException: Connection timed out: connect

    I tried to find a solution on Google without success. I tried the above (with port 110 and 143) but also without success.
    Can you please give some more troubleshoot on what might be wrong?

    Thanks in advance

    Renaud L.

    Reply

Leave a Comment

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions and frequently asked interview questions.