Sending Emails is the most common task for most backend applications. Java provides Java Mail API - a platform and protocol-independent framework to build mail and messaging applications. You can find documentation here.
In this guide, you will get simple steps to set up JavaMail in your Java Project + implement JavaMail API to build and send emails on SMTP protocol and use the tool MailHog to test that emails are gone in a Mail Inbox.
Requirements
- Basic knowledge on Docker
- Basic knowledge on Java
- These Maven dependencies 👇🏽
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>javax.mail</artifactId>
<version>1.6.2</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
Set the email properties
To send an email, you should define some SMTP properties in the application.properties, it is usually a good practice to set config and properties values in the application.properties file.
spring.mail.host=localhost
spring.mail.port=1025
spring.mail.username=user123
spring.mail.password=admin
After that, you should retrieve all those properties in a POJO
@Getter
@Setter
@Component
@Validated
@ConfigurationProperties(prefix = "spring.mail")
public class AppConfigs {
@NotNull
private String host;
@NotNull
private int port;
@NotNull
private String username;
@NotNull
private String password;
}
@ConfigurationProperties
classes available in Spring Boot, but the accessors (getters/setters) of the class itself are not meant to be used directly.Finally, in a Mailservice class we can set properties for sending email
private Properties getProperties() {
Properties properties = new Properties();
properties.put("mail.smtp.host", appConfigs.getHost());
properties.put("mail.smtp.port", appConfigs.getPort());
properties.put("mail.user", appConfigs.getPort());
properties.put("mail.password", appConfigs.getPort());
return properties;
}
Set the email headers
Now you can define the email headers (sender, receiver, subject and date)
MimeMessage message = new MimeMessage(session);
message.setFrom("sender-test@example.com");
message.setRecipients(RecipientType.TO, "receiver-test@example.com");
message.setSubject("Testing Javax Mail and MailHog");
message.setSentDate(new Date());
Set the email body
For this tutorial, we will use an HTML email template, which is located in resources/static/mail
MimeBodyPart messageBodyPart = new MimeBodyPart();
File htmlFile = getFile("classpath:static/mail/content.html");
String htmlFileContent = new String(readAllBytes(htmlFile.toPath()));
messageBodyPart.setContent(htmlFileContent, "text/html");
Set the image body
To use an image in the body of your mail, you can load an image from your disk and print it in email
MimeBodyPart imageBodyPart = new MimeBodyPart();
File attachmentFile = getFile("classpath:static/attachments/email-logo.png");
imageBodyPart.setHeader("Content-Id","<logoImage>");
imageBodyPart.setDisposition(MimeBodyPart.INLINE);
imageBodyPart.attachFile(attachmentFile);
Set the mail sender
Once all the parts of the mail have been created, you can assemble them with the class Multipart, then send the mail
Multipart multipart = new MimeMultipart();
multipart.addBodyPart(messageBodyPart);
multipart.addBodyPart(imageBodyPart);
message.setContent(multipart);
send(message);
The whole MailService class will look like this
@Service
@RequiredArgsConstructor
public class MailService {
private final AppConfigs appConfigs;
public void sendSimpleMail() {
Properties properties = getProperties();
Session session = Session.getInstance(properties);
try {
MimeMessage message = new MimeMessage(session);
message.setFrom("sender-test@example.com");
message.setRecipients(RecipientType.TO, "receiver-test@example.com");
message.setSubject("Testing Javax Mail and MailHog");
message.setSentDate(new Date());
MimeBodyPart messageBodyPart = new MimeBodyPart();
File htmlFile = getFile("classpath:static/mail/content.html");
String htmlFileContent = new String(readAllBytes(htmlFile.toPath()));
messageBodyPart.setContent(htmlFileContent, "text/html");
MimeBodyPart imageBodyPart = new MimeBodyPart();
File attachmentFile = getFile("classpath:static/attachments/email-logo.png");
imageBodyPart.setHeader("Content-Id","<logoImage>");
imageBodyPart.setDisposition(MimeBodyPart.INLINE);
imageBodyPart.attachFile(attachmentFile);
Multipart multipart = new MimeMultipart();
multipart.addBodyPart(messageBodyPart);
multipart.addBodyPart(imageBodyPart);
message.setContent(multipart);
send(message);
}catch (Exception exception) {
System.out.println("Sending Email failed, error : " + exception.getMessage());
}
}
private Properties getProperties() {
Properties properties = new Properties();
properties.put("mail.smtp.host", appConfigs.getHost());
properties.put("mail.smtp.port", appConfigs.getPort());
properties.put("mail.user", appConfigs.getPort());
properties.put("mail.password", appConfigs.getPort());
return properties;
}
}
The part where we set the content ID for the image is bind with the src element in the HTML content of our email template.
You can get this line here.
Email reception with MailHog
To be able to test that email will actually go into the client inbox, we will use a tool called Mailhog.
Now that we have configured our Mail Service class we can set up our local server for testing that email is sent. First of all you should create a env file
where you can store all the config for the Mailhog local server.
{
"server name": {
"name": "mailhog",
"host": "localhost",
"port": "1025",
"username": "user123",
"password": "admin",
"mechanism": "PLAIN"
}
}
After that, we can modify a Dockerfile inspired by Mailhog documentation
# MailHog Dockerfile
FROM golang:1.18-alpine as builder
# Install MailHog:
RUN apk --no-cache add --virtual build-dependencies \\
git \\
&& mkdir -p /root/gocode \\
&& export GOPATH=/root/gocode \\
&& go install github.com/mailhog/MailHog@latest
FROM alpine:3
RUN adduser -D -u 1000 mailhog
COPY --from=builder /root/gocode/bin/MailHog /usr/local/bin/
USER mailhog
WORKDIR /home/mailhog
COPY env.smtp .
ENTRYPOINT MailHog -outgoing-smtp ./env.smtp
# Expose the SMTP and HTTP ports:
EXPOSE 1025 8025
COPY env.smtp .
part is necessary to run Mailhog image as an entrypoint with option for mailhog CLI.Now you can build your Mailhog local image with this docker command in the root directory of your project
docker build --no-cache . -t mailhog-local
Then run the Image in a brand-new container with this command
docker run -d --name mailhog-local -p 1025:1025 -p 8025:8025 mailhog-local
Once the container is up, you can access your local instance of Mailhog via localhost:8085
Now we can test email sending via a simple spring boot controller
import com.example.demo.service.MailService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController("/mail")
@RequiredArgsConstructor
public class MailController {
private final MailService mailService;
@GetMapping("/send-simple-mail")
void sendMail() {
mailService.sendSimpleMail();
}
}
To test our application, we can start our spring boot server with this command
mvn spring-boot:run
Once the app server is up, we can test the URL with Curl
curl localhost:8080/send-simple-mail
And we get the result in our Mailhog UI ⚡️
I hope you enjoyed reading this, and I'm curious to hear if this tutorial helped you. Please let me know your thoughts below in the comments. Don't forget to subscribe to my newsletter to avoid missing my upcoming blog posts.
You can also find me here LinkedIn • Twitter • GitHub or Medium
You can found the entire code for this tutorial on my GitHub.