Send Email in Java

Send Email in Java

Introduction

        Sending an email is one of the most important and most frequently used functionalities in a technology organization. A software developer should know how this is done. This post will give you a comprehensive overview of sending emails using Java mail libraries. This post will give you an overview of the following:
  1. Send a plain text email in HTML format.
  2. Create an attachment and send an email.
  3. Use an existing file as an attachment and send an email. 
As RESTful web services are commonly used today, I will be using Dropwizard for building out the email functionality as RESTful APIs. Hence here are what I will be using in this post:
  1. Java mail libraries: To connect to email service provider, compose and send emails
  2. Gmail: Email service provider
  3. Dropwizard: For developing Email functionalities as RESTful web services
        Dropwizard is one of the most popular and most used frameworks for building microservices.
I am assuming that you have a Basic Knowledge of Dropwizard and have a Basic Dropwizard Application running in your machine. If not, please check my blog post on Basic Dropwizard Application by going to the link: Dropwizard Tutorial.

Requirements to Run the Application:
  1. Java
  2. Maven
  3. IDE of your choice
Once you have a Basic Dropwizard Application up and running in your machine, the steps mentioned below are required to add the email related functionalities.

Step 1: Maven Dependencies to be added in pom.xml

Add Java Mail libraries to the project by using the following dependency in the pom.xml:
  <dependency>
   <groupId>javax.mail</groupId>
   <artifactId>mail</artifactId>
   <version>1.4.7</version>
  </dependency>

  <dependency>
   <groupId>javax.mail</groupId>
   <artifactId>javax.mail-api</artifactId>
   <version>1.6.2</version>
  </dependency>
Here is the full pom.xml:
<?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.aj.dropwizardemail</groupId>
 <artifactId>DropwizardEmail</artifactId>
 <version>1.0.0</version>


 <properties>
  <dropwizard.version>1.3.9</dropwizard.version>
        <jdk.version>1.8</jdk.version>
  <packaging>jar</packaging>
 </properties>

 <dependencies>

  <dependency>
            <groupId>io.dropwizard</groupId>
            <artifactId>dropwizard-core</artifactId>
            <version>${dropwizard.version}</version>
        </dependency>

  <dependency>
   <groupId>javax.mail</groupId>
   <artifactId>mail</artifactId>
   <version>1.4.7</version>
  </dependency>

  <dependency>
   <groupId>javax.mail</groupId>
   <artifactId>javax.mail-api</artifactId>
   <version>1.6.2</version>
  </dependency>

 </dependencies>

 <build>
  <plugins>
   <plugin>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.0</version>
    <configuration>
     <source>1.8</source>
     <target>1.8</target>
    </configuration>
   </plugin>
   <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <version>3.1.1</version>
   </plugin>
   <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <version>3.2.1</version>
    <configuration>
     <createDependencyReducedPom>true</createDependencyReducedPom>
     <filters>
      <filter>
       <artifact>*:*</artifact>
       <excludes>
        <exclude>META-INF/*.SF</exclude>
        <exclude>META-INF/*.DSA</exclude>
        <exclude>META-INF/*.RSA</exclude>
       </excludes>
      </filter>
     </filters>
    </configuration>
    <executions>
     <execution>
      <phase>package</phase>
      <goals>
       <goal>shade</goal>
      </goals>
      <configuration>
       <transformers>
        <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer" />
        <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
         <mainClass>com.aj.dropwizardemail.DropwizardEmailApplication</mainClass>
        </transformer>
       </transformers>
      </configuration>
     </execution>
    </executions>
   </plugin>
  </plugins>
 </build>
</project>

Step 2: Create Email Service Class

This class has all the logic to connect to email service provider, compose and send emails. There are 3 objects that are used to send emails:
  1. Java Properties object
  2. Mail Session object
  3. MimeMessage object 
Properties Object is used for adding email host related configurations. Using this properties object a Mail Session Object is created using the email username and email password.
I have used my Gmail ID: techdeveloper.aj@gmail.com and I have left the password field empty. For the code to work, please use your Gmail ID and password here.
Here is the related code:
private Session getSession() {
        //Gmail Host
        String host = "smtp.gmail.com";
        String username = "techdeveloper.aj@gmail.com";
        //Enter your Gmail password
        String password = "";

        Properties prop = new Properties();
        prop.put("mail.smtp.auth", true);
        prop.put("mail.smtp.starttls.enable", "true");
        prop.put("mail.smtp.host", host);
        prop.put("mail.smtp.port", 587);
        prop.put("mail.smtp.ssl.trust", host);

        return Session.getInstance(prop, new Authenticator() {
            @Override
            protected PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication(username, password);
            }
        });
    }
Using the Mail Session object created above, a MimeMessage Object needs to be created. From, to, subject and content are set to the MimeMessage Object.
A MimeBodyPart object is created in which the encoding of text/html is set so that our message is styled in the HTML format.
MimeMultipart object is used to enclose the MimeBodyPart object and this is set as content to the MimeMessage Object.
send() method of Transport object is then used to send the email. Code to send email is shown below.

Send Plain Text Email in HTML format

Here is the code:
//Send email with body only without any attachment.
    public String sendMail() {
        String result;
        try {
            logger.info("Sending Email to {}", to);
            Session session = getSession();
            try {
                // Create a default MimeMessage object.
                MimeMessage message = new MimeMessage(session);
                // Set From
                message.setFrom(new InternetAddress(from, fromName));
                // Set To
                message.addRecipient(Message.RecipientType.TO, new InternetAddress(to));
                // Set Subject
                message.setSubject(emailSubject);
                MimeBodyPart mimeBodyPart = new MimeBodyPart();
                mimeBodyPart.setContent(msg, "text/html");
                Multipart multipart = new MimeMultipart();
                multipart.addBodyPart(mimeBodyPart);
                message.setContent(multipart);
                // Send message
                Transport.send(message);
                logger.info(successResult);
                result = successResult;
            } catch (MessagingException ex) {
                logger.error("Failed to send email to: {}", to);
                logger.error("Exception is: {}", ex.getMessage());
                result = failureResult;
            }
        }
        catch (Exception e){
            logger.error("Exception in EmailService.sendMail(): ",e.getMessage());
            result = failureResult;
        }
        return result;
    }

Send Email with Attachment

For sending attachments in email, as shown in the code below, create another MimeBodyPart object and attach the file to it. Here is the code:
//Fetch the file from the specified file path and send email by attaching the file fetched.
    public String sendMailAttachment() {
        String result;
        try {
            logger.info("Sending Email to {}", to);
            Session session = getSession();
            try {
                // Create a default MimeMessage object.
                MimeMessage message = new MimeMessage(session);
                // Set From
                message.setFrom(new InternetAddress(from, fromName));
                // Set To
                message.addRecipient(Message.RecipientType.TO, new InternetAddress(to));
                // Set Subject
                message.setSubject(emailSubject);
                MimeBodyPart mimeBodyPart = new MimeBodyPart();
                mimeBodyPart.setContent(msg, "text/html");
                MimeBodyPart mimeBodyPartAttachment = new MimeBodyPart();
                mimeBodyPartAttachment.attachFile(new File("src/main/resources/attachment/Hello.txt"));

                Multipart multipart = new MimeMultipart();
                multipart.addBodyPart(mimeBodyPart);
                multipart.addBodyPart(mimeBodyPartAttachment);
                message.setContent(multipart);
                // Send message
                Transport.send(message);
                logger.info(successResult);
                result = successResult;
            } catch (MessagingException ex) {
                logger.error("Failed to send email to: {}", to);
                logger.error("Exception is: {}", ex.getMessage());
                result = failureResult;
            }
        }
        catch (Exception e){
            logger.error("Exception in EmailService.sendMailAttachment(): ",e.getMessage());
            result = failureResult;
        }
        return result;
    }

Create an attachment file and send it in the Email

Create a file:
private File getTextFile() throws IOException {
        String text = "Hello World!!!";
        BufferedWriter bufferedWriter = null;
        File file = null;
        try {
            file = new File("Hello.txt");
            bufferedWriter = new BufferedWriter(new FileWriter(file));
            bufferedWriter.write(text);
        } catch ( IOException e ) {
            logger.error("Error in creating text file: {}", e.getMessage());
        } finally {
            if ( bufferedWriter != null ) {
                bufferedWriter.close();
            }
        }
        return file;
    }
Attach the newly created file and send an email:
//Create an attachment and send email.
    public String sendMailCreateAttachment() {
        String result;
        try {
            logger.info("Sending Email to {}", to);
            Session session = getSession();
            try {
                // Create a default MimeMessage object.
                MimeMessage message = new MimeMessage(session);
                // Set From
                message.setFrom(new InternetAddress(from, fromName));
                // Set To
                message.addRecipient(Message.RecipientType.TO, new InternetAddress(to));
                // Set Subject
                message.setSubject(emailSubject);
                MimeBodyPart mimeBodyPart = new MimeBodyPart();
                mimeBodyPart.setContent(msg, "text/html");
                File file = getTextFile();
                MimeBodyPart mimeBodyPartAttachment = new MimeBodyPart();
                mimeBodyPartAttachment.attachFile(file);
                Multipart multipart = new MimeMultipart();
                multipart.addBodyPart(mimeBodyPart);
                multipart.addBodyPart(mimeBodyPartAttachment);
                message.setContent(multipart);
                // Send message
                Transport.send(message);
                logger.info(successResult);
                result = successResult;
            } catch (MessagingException ex) {
                logger.error("Failed to send email to: {}", to);
                logger.error("Exception is: {}", ex.getMessage());
                result = failureResult;
            }
        }
        catch (Exception e){
            logger.error("Exception in EmailService.sendMailCreateAttachment(): ",e.getMessage());
            result = failureResult;
        }
        return result;
    }
Here is the full class: EmailService.java:
package com.aj.dropwizardemail.service;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;

public class EmailService {

    private static final Logger logger = LoggerFactory.getLogger(EmailService.class);
    // Recipient's Email ID
    public static final String to = "techdeveloper.aj@gmail.com";
    // Sender's Email ID
    public static final String from = "techdeveloper.aj@gmail.com";
    // Sender's Name
    public static final String fromName = "Aj Tech Developer";
    public static final String emailSubject = "Mail from Dropwizard Email Application";
    public static final String msg = "<p>Hi</p>\n" +
            "<p>This is a mail from Dropwizard Email Application!!!</p>\n" +
            "Regards<br>\n" +
            "Aj Tech Developer";
    public static final String successResult = "Mail sent successfully.";
    public static final String failureResult = "Failed to send mail.";

    //Send email with body only without any attachment.
    public String sendMail() {
        String result;
        try {
            logger.info("Sending Email to {}", to);
            Session session = getSession();
            try {
                // Create a default MimeMessage object.
                MimeMessage message = new MimeMessage(session);
                // Set From
                message.setFrom(new InternetAddress(from, fromName));
                // Set To
                message.addRecipient(Message.RecipientType.TO, new InternetAddress(to));
                // Set Subject
                message.setSubject(emailSubject);
                MimeBodyPart mimeBodyPart = new MimeBodyPart();
                mimeBodyPart.setContent(msg, "text/html");
                Multipart multipart = new MimeMultipart();
                multipart.addBodyPart(mimeBodyPart);
                message.setContent(multipart);
                // Send message
                Transport.send(message);
                logger.info(successResult);
                result = successResult;
            } catch (MessagingException ex) {
                logger.error("Failed to send email to: {}", to);
                logger.error("Exception is: {}", ex.getMessage());
                result = failureResult;
            }
        }
        catch (Exception e){
            logger.error("Exception in EmailService.sendMail(): ",e.getMessage());
            result = failureResult;
        }
        return result;
    }

    //Fetch the file from the specified file path and send email by attaching the file fetched.
    public String sendMailAttachment() {
        String result;
        try {
            logger.info("Sending Email to {}", to);
            Session session = getSession();
            try {
                // Create a default MimeMessage object.
                MimeMessage message = new MimeMessage(session);
                // Set From
                message.setFrom(new InternetAddress(from, fromName));
                // Set To
                message.addRecipient(Message.RecipientType.TO, new InternetAddress(to));
                // Set Subject
                message.setSubject(emailSubject);
                MimeBodyPart mimeBodyPart = new MimeBodyPart();
                mimeBodyPart.setContent(msg, "text/html");
                MimeBodyPart mimeBodyPartAttachment = new MimeBodyPart();
                mimeBodyPartAttachment.attachFile(new File("src/main/resources/attachment/Hello.txt"));

                Multipart multipart = new MimeMultipart();
                multipart.addBodyPart(mimeBodyPart);
                multipart.addBodyPart(mimeBodyPartAttachment);
                message.setContent(multipart);
                // Send message
                Transport.send(message);
                logger.info(successResult);
                result = successResult;
            } catch (MessagingException ex) {
                logger.error("Failed to send email to: {}", to);
                logger.error("Exception is: {}", ex.getMessage());
                result = failureResult;
            }
        }
        catch (Exception e){
            logger.error("Exception in EmailService.sendMailAttachment(): ",e.getMessage());
            result = failureResult;
        }
        return result;
    }

    //Create an attachment and send email.
    public String sendMailCreateAttachment() {
        String result;
        try {
            logger.info("Sending Email to {}", to);
            Session session = getSession();
            try {
                // Create a default MimeMessage object.
                MimeMessage message = new MimeMessage(session);
                // Set From
                message.setFrom(new InternetAddress(from, fromName));
                // Set To
                message.addRecipient(Message.RecipientType.TO, new InternetAddress(to));
                // Set Subject
                message.setSubject(emailSubject);
                MimeBodyPart mimeBodyPart = new MimeBodyPart();
                mimeBodyPart.setContent(msg, "text/html");
                File file = getTextFile();
                MimeBodyPart mimeBodyPartAttachment = new MimeBodyPart();
                mimeBodyPartAttachment.attachFile(file);
                Multipart multipart = new MimeMultipart();
                multipart.addBodyPart(mimeBodyPart);
                multipart.addBodyPart(mimeBodyPartAttachment);
                message.setContent(multipart);
                // Send message
                Transport.send(message);
                logger.info(successResult);
                result = successResult;
            } catch (MessagingException ex) {
                logger.error("Failed to send email to: {}", to);
                logger.error("Exception is: {}", ex.getMessage());
                result = failureResult;
            }
        }
        catch (Exception e){
            logger.error("Exception in EmailService.sendMailCreateAttachment(): ",e.getMessage());
            result = failureResult;
        }
        return result;
    }

    private Session getSession() {
        //Gmail Host
        String host = "smtp.gmail.com";
        String username = "techdeveloper.aj@gmail.com";
        //Enter your Gmail password
        String password = "";

        Properties prop = new Properties();
        prop.put("mail.smtp.auth", true);
        prop.put("mail.smtp.starttls.enable", "true");
        prop.put("mail.smtp.host", host);
        prop.put("mail.smtp.port", 587);
        prop.put("mail.smtp.ssl.trust", host);

        return Session.getInstance(prop, new Authenticator() {
            @Override
            protected PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication(username, password);
            }
        });
    }

    private File getTextFile() throws IOException {
        String text = "Hello World!!!";
        BufferedWriter bufferedWriter = null;
        File file = null;
        try {
            file = new File("Hello.txt");
            bufferedWriter = new BufferedWriter(new FileWriter(file));
            bufferedWriter.write(text);
        } catch ( IOException e ) {
            logger.error("Error in creating text file: {}", e.getMessage());
        } finally {
            if ( bufferedWriter != null ) {
                bufferedWriter.close();
            }
        }
        return file;
    }
}

Step 3: Add RESTFul APIs

EmailResource.java: 

This file has 3 APIs:
  1. GET API to send Plain Text Email in HTML format.
  2. GET API to send an Email with an attachment.
  3. GET API to create an attachment file and send an Email with it.
Here is the code:
package com.aj.dropwizardemail.resource;

import com.aj.dropwizardemail.service.EmailService;
import com.codahale.metrics.annotation.Timed;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.HashMap;
import java.util.Map;


@Path("/email")
@Produces(MediaType.APPLICATION_JSON)
public class EmailResource {

    private static final Logger logger = LoggerFactory.getLogger(EmailResource.class);

    private final EmailService emailService;

    public EmailResource(EmailService emailService) {
        this.emailService = emailService;
    }

 @Timed
 @GET
    @Path("/send")
    @Produces(MediaType.APPLICATION_JSON)
    public Response sendMail() {
  Map<String, String> response = new HashMap<>();
  String result = emailService.sendMail();
  response.put("message", result);
  return Response.ok(response).build();
 }


    @Timed
    @GET
    @Path("/send/attachment")
    @Produces(MediaType.APPLICATION_JSON)
    public Response sendMailAttachment() {
        Map<String, String> response = new HashMap<>();
        String result = emailService.sendMailAttachment();
        response.put("message", result);
        return Response.ok(response).build();
    }

    @Timed
    @GET
    @Path("/send/attachment/create")
    @Produces(MediaType.APPLICATION_JSON)
    public Response sendMailCreateAttachment() {
        Map<String, String> response = new HashMap<>();
        String result = emailService.sendMailCreateAttachment();
        response.put("message", result);
        return Response.ok(response).build();
    }
}

Step 4: Application Class

Application class is the entry point for any Dropwizard application. It will have to extend the io.dropwizard. Application class and implement the initialize(Bootstrap<Configuration>) 
and run(Configuration, Environment) methods. Thus the runtime environment of the application is setup.
In this example I have used my custom Configuration: DropwizardEmailConfiguration which extends io.dropwizard.Configuration
The run method is called from public static void main(String[] args) {} method.
In the Application class, all the resources should be registered. You can see how I am setting up the following in the Application class:
  1. Configuration class: DropwizardEmailConfiguration
  2. Health check resource: DropwizardEmailHealthCheckResource
  3. Other resources: PingResource and EmailResource
DropwizardEmailApplication.java:
package com.aj.dropwizardemail;

import com.aj.dropwizardemail.resource.DropwizardEmailHealthCheckResource;
import com.aj.dropwizardemail.resource.EmailResource;
import com.aj.dropwizardemail.resource.PingResource;
import com.aj.dropwizardemail.service.EmailService;
import io.dropwizard.Application;
import io.dropwizard.setup.Bootstrap;
import io.dropwizard.setup.Environment;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


public class DropwizardEmailApplication extends Application<DropwizardEmailConfiguration> {

    private static final Logger logger = LoggerFactory.getLogger(DropwizardEmailApplication.class);

 public static void main(String[] args) throws Exception {
  new DropwizardEmailApplication().run("server", args[0]);
 }

    @Override
    public void initialize(Bootstrap<DropwizardEmailConfiguration> b) {
 }

 @Override
 public void run(DropwizardEmailConfiguration config, Environment env) {
        logger.info("Registering RESTful API resources");
  env.jersey().register(new PingResource());
  env.healthChecks().register("DropwizardEmailHealthCheck",
    new DropwizardEmailHealthCheckResource(config));
  env.jersey().register(new EmailResource(new EmailService()));
 }
}

Project Setup:

For Java Setup, please refer to:  Java Setup
For Maven Setup, please refer to: Maven Setup
For Git and Project Setup, please refer to: Git and Project Setup

Run Application:

1. To run application in your IDE use:
    Program arguments: src/main/resources/dropwizardemail.yml

2. To run JAR from command prompt:
     Build jar by using command:   
   mvn clean install
     Run JAR by using command in Project folder location:
   java -jar target\DropwizardEmail-1.0.0.jar src\main\resources\dropwizardemail.yml

Important settings before running the APIs:

1. SMTP access to Gmail is disabled by default. To permit our application to send emails using your Gmail account follow these steps

In the Security setting, set ‘Allow less secure apps’ to ON as per the screenshots below


2. Enter you Gmail password in the file EmailService.java

API calls and results:

1. GET API to send Plain Text Email in HTML format.
    http://localhost:4000/email/send
Most of the Anti Virus programs block sending of Email from the computer through an internal application. Hence if you get an error, then you will have to disable your Anti Virus program while calling these Email sending APIs
Here are the error screenshots due to Anti Virus:

Disable Anti Virus Program: 
For Avast Anti Virus, from System Tray use the following:

API working fine after disabling Anti Virus program.


    2. GET API to send an Email with an attachment.
        http://localhost:4000/email/send/attachment
3. GET API to create an attachment file and send an Email with it.
    http://localhost:4000/email/send/attachment/create



Other than these APIs, this application has the following APIs:
1. GET API for Application Health Check:
2. GET API to Ping and test if the application is up and running: 
3. POST API to Ping and test if the application is up and running: 
    JSON Request Body:
    {
     "input": "ping"
    }
4. GET Admin API to see application metrics: Dropwizard provides this Admin API. As I have set adminContextPath as: /admin in dropwizardmongodb.yml the link I need to use in any browser is: http://localhost:4000/admin/
You can click on individual links on this page to see different application metrics.

Conclusion and GitHub link:

    In this post I have shown you as to how you can send emails using Java mail libraries and also expose the email sending functionalities as RESTful APIs. The code used in this post is available on GitHub.
    Learn the most popular and trending technologies like Machine Learning, Chatbots, Internet of Things (IoT), Big Data Processing, Elastic Stack, Angular 5, Akka HTTP, Play Framework, Dropwizard, Docker, Netflix Eureka, Netflix Zuul, Spring Cloud, Spring Boot, Flask and RESTful Web Service integration with MongoDB, Kafka, Redis, Aerospike, MySQL DB in simple steps by reading my most popular blog posts at Software Developer Central.
    If you like my post, please feel free to share it using the share button just below this paragraph or next to the heading of the post. You can also tweet with #SoftwareDeveloperCentral on Twitter. To get a notification on my latest posts or to keep the conversation going, you can follow me on Twitter or Instagram. Please leave a note below if you have any questions or comments.



Comments

Popular Posts

REST API using Play Framework with Java

Asynchronous Processing (@Async) in Spring Boot

Elasticsearch, Logstash, Kibana Tutorial: Load MySQL Data into Elasticsearch