#TechBite: Spring Mail with MailHog or Gmail

Etimbuk U
5 min readFeb 10, 2020

A great week to be writing a TechBite… The UK leaves the EU. Whoops!! 👀 It's a TechBite, not a PolitcsBite 🤷‍♂

In today's post, we will be taking a look at sending emails using Spring Email. To illustrate a mailbox, we will be using MailHog and later on use Gmail.

MailHog, What is it? 🤔

In very simple terms, MailHog is an email testing tool that developers (and probably anyone too! 👀) can utilize to test email sending (and recipients).

MailHog UI

My key attractions to MailHog includes

  • Ease of setup;
  • Ability to list, retrieve and delete messages via a JSON API and also a UI
  • Ability to download MIME parts
  • It has a Docker image that we can instantiate into a container.
Other features as listed here

So how do we use MailHog with Spring Email?

  • We will need to create a Spring project. For this post, we will be using spring-boot. We can do this via the CLI or from htps://start.spring.io. For this post, we will be using the CLI
  • Pull and run MailHog docker image
  • Update application.properties or application.yml file with configuration values needed to connect the MailHog SMTP server. For this post, we will be using application.properties
  • Write code that sends emails (who would have thought!?😄)
  • Run/test the application

Creating the project

To create the project with required dependencies, we will be running the below command

spring init -d=web,lombok,mail -n=spring-mailhog-gmail --package-name=dev.etimbuk --description="Using Spring Mail with MailHog and Gmail" -g=dev.etimbuk --build=gradle spring-mailhog-gmail
  • spring init. Initialize a new project using Spring Initializr (start.spring.io)
  • -d=web,lombok,mail. This instructs the initializer that we will need web, Lombok and mail dependencies;
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-mail'
implementation 'org.springframework.boot:spring-boot-starter-web'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
}
  • -n=spring-mailhog-gmail.Instructs the initializer that we need the spring-web, Lombok and spring-mail dependencies;
  • — package-name. This will create our base package for the project
  • — description. Gives our project description.
  • — build=gradle. Tells the initializer we want a Gradle project. The default if this not specified is a maven project;
  • spring-mailhog-gmail. Here we tell the initializer to extract into a folder named spring-mailhog-gmail. When no value specified the command produces a demo.zip
Project structure

Pull and run MailHog Docker Image

Before we run the MailHog Docker image, it is worth noting that we can also install MailHog via brew.

docker run -d --name mailhog -p 8025:8025 -p 1025:1025 mailhog/mailhog
Our Mailhog container viewed from Portainer. For a bit of info on Portainer see here

The above command pulls the MailHog Docker image (if it does not already exist) and runs it using mailhog as the container name and makes the Web UI accessible on port 8025 and SMTP available on port 1025. It is also worth noting that this will run using in-memory storage.

Update project configuration

For this article, what we need is the host address and port number for the MailHog SMTP server. The configuration will be as below

## Spring Boot mail server configuration for MailHog
spring.mail.host=127.0.0.1
spring.mail.port=1025

Code Time 👯

Before we begin writing code it is worth briefly consult the Javadocs for the Java mail classes in Spring framework which will enable us to send emails.

  • MailSender. This interface defines a strategy for sending simple mails. Can be
    implemented for a variety of mailing systems due to the simple requirements.
  • JavaMailSender. This interface extends MailSender. It supports MIME messages and is typically used in conjunction with the MimeMessageHelper
    class for convenient creation of JavaMail MimeMessages, including attachments, etc.
  • JavaMailSenderImpl. Production implementation of the JavaMailSender interface, supporting both JavaMail MimeMessage and Spring SimpleMailMessage. It can also be used as a plain org.springframework.mail.MailSender.
  • MimeMessageHelper. Its simply a helper class for populating MimeMessage.
  • MimeMessage. This class represents a MIME style email message. It implements the Message abstract class and the MimePart interface.

So what do we need here? 🤔 🤔

Following on from our understanding of what the key classes and interfaces are, we will need

  • A JavaMailSender, with the mail server host, port and any other properties needed;
@Bean
public
JavaMailSender javaMailSender() {
JavaMailSenderImpl javaMailSender = new JavaMailSenderImpl();
javaMailSender.setHost(host);
javaMailSender.setPort(port);

Properties properties = new Properties();
properties.setProperty("mail.transport.protocol", "smtp");

javaMailSender.setJavaMailProperties(properties);
return javaMailSender;
}
  • A MimeMessage, which would be used by MimeMessageHelper to build our email. Depending on the MimeMessageHelper constructor we instantiate MimeMessageHelper with, we can specify if our email will be multipart (can create a message that supports alternative texts, inline elements, and attachments)
MimeMessage message = mailSender.createMimeMessage();

MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(message, true);//instantiates a multipart message

mimeMessageHelper.setTo(emailData.getRecipient());
mimeMessageHelper.setFrom(from);
mimeMessageHelper.setSubject(emailData.getSubject());
mimeMessageHelper.setText(emailData.getMessage());
...
mimeMessageHelper.addAttachment(attachment.getFilename(),
attachment.getData(), attachment.getContentType());
  • Send the email using an instance of JavaMailSender.
mailSender.send(message);

Testing with MailHog

To enable us to test things out, we will create a controller which receives a request to send an email

//Snippet from our controller class
@PostMapping("send")
public ResponseEntity<EmailSendResponse> sendEmail(@RequestBody EmailSendRequest emailSendRequest) {

try {
emailService.sendEmail(emailSendRequest.getSender(), EmailData.from(emailSendRequest));

return ResponseEntity.status(OK).body(EmailSendResponse.builder()
.success(true)
.message("Email sent successfully.")
.build());

} catch (Exception exc) {
return ResponseEntity.status(INTERNAL_SERVER_ERROR).body(EmailSendResponse.builder()
.success(false)
.message(String.format("Failed to send email due to %s", exc.getMessage()))
.build());
}
}
Making a request to send email resource
Our sent email received on MailHog server

Testing with Gmail

To test with Gmail, we would need to update our configurations in the application.properties (or application.yml) file to look as below.

## Spring Boot mail server configuration for Gmail
spring.mail.host=smtp.gmail.com
spring.mail.port=587
spring.mail.username=<YOUR_GMAIL_USERNAME>
spring.mail.password=<GMAIL_PASSWORD_OR_16_CHARACTERS_FROM_APP_PASSWORD>

With regards to the password in our above Gmail configuration, this can be your Gmail password or an App Password which can be generated by following instructions here.

Our JavaMailSender bean/instance will also be updated to look as below

@Bean
public
JavaMailSender javaMailSender() {
JavaMailSenderImpl javaMailSender = new JavaMailSenderImpl();
javaMailSender.setHost(host);
javaMailSender.setPort(port);
javaMailSender.setUsername(username);
javaMailSender.setPassword(password);

Properties properties = new Properties();
properties.put("mail.transport.protocol", "smtp");
properties.put("mail.smtp.auth", "true");
properties.put("mail.smtp.starttls.enable", "true");
properties.put("mail.debug", "true");

javaMailSender.setJavaMailProperties(properties);
return javaMailSender;
}

Now that we have updated our configurations, we can restart and send our request as usual

The recipient is my Gmail address
Email received

Thanks again for reading till the end, as usual, the code for this can be found on GitHub. I am looking forward to your comments/feedback and questions. 👍

References

Installing Spring CLI

--

--

Etimbuk U

Java | Flutter | Android | Some JavaScript | API Design