Receive emails with SubEtha SMTP and Spring Boot
Tags: java, subethasmtp, springboot, email
Published: 2020-07-13 07:51:39

Some years ago I needed to write a Java application that receives emails and process some business stuff on those. It wasn't an easy task as I didn't find a lot of information. Because of that I decided, one day, I'll write about it and maybe that could helps 🙂.

Full source code available [here](https://github.com/redamessoudi/subethasmtp-springboot).

# Context
## Why ?
You would ask why do you need that ? I would say :

> *Business requirements can surprise you every day*

Below a small list of some use cases when this incoming emails processing can be helpful.

* Testing : Can be good option for integration testing the email capabilities of your services/applications (The old [FakeSMTP](http://nilhcem.com/FakeSMTP/) is a good GUI example)
* Analyse received emails and extract some specific information
* ...

## What ?
SubEtha SMTP is low-level API for writing almost any kind of SMTP mail-receiving application.

To avoid you a long history presentation, the most updated version of SubEtha SMTP is a [fork](https://github.com/davidmoten/subethasmtp) by [David Moten](https://davidmoten.github.io/) (many thanks to him for his excellent work and keeping this library updated). We'll use this fork in this post.


I think no need to describe what's [Spring Boot](https://spring.io/projects/spring-boot) in nowadays.


# Let's code

Before starting the code, I suggest to see how we can send an email via terminal. We'll need that to send an email to our future emails receiver application.

## Send email with cURL

Below an example of sending email to specific mail server with parameters like from, recipient, auth and the content of the email.
```bash
curl --url 'smtp://localhost:25000' \                                     
  --mail-from 'customer-address@mail.com' \
  --mail-rcpt 'info@marketing.company.com' \
  --user 'superus3r:passw0rd' \
  -T <(echo -e 'From: customer-address@mail.com\nTo: info@marketing.company.com\nSubject: cURL Test\n\nHello, this is the content')
```


## SubEtha dependency

Here we add the maven dependency of SubEtha SMTP.
```XML
<dependency>
    <groupId>com.github.davidmoten</groupId>
    <artifactId>subethasmtp</artifactId>
    <version>5.2.4</version>
</dependency>
```


## Start the embedded SMTP server

It's very easy to start a simple SMTP server with the library. Just create/build an instance of SMTPServer with the right parameters like port and start this instance.
```JAVA
// Build the embedded SMTP server
SMTPServer smtpServer = SMTPServer.port(25000).build();
// Start server asynchronously 
smtpServer.start();
```
Now our SMTP server is started but not fully ready to receive emails. We need to implement a MessageListener to extract important data like *from* and *recipient* addresses but also the *subject* and the *body* of the received email.

For that we can implement the *SimpleMessageListener* interface :
```JAVA
public class MarketingMailListener implements SimpleMessageListener {

    private static final String MARKETING_DOMAIN = "@marketing.company.com";

    /**
     * Do some business logic here
     */
    @Override
    public boolean accept(String from, String recipient) {
        return recipient != null && recipient.endsWith(MARKETING_DOMAIN);
    }

    @Override
    public void deliver(String from, String recipient, InputStream data) 
    throws TooMuchDataException, IOException {
        System.out.println("deliver message of MARKETING department");
        System.out.println("From : "+from);
        System.out.println("Recipient : "+recipient);
    }
```
As you can see here, I added a simple business rule inside *accept* method to handle only emails sent to marketing department.

The *accept* method is responsible for defining if the received message will be proceeded by this listener or not.

The *deliver* method is responsible for extracting :

* *From* : The sender address
* *Recipient* : The receiver address
* *Data* : It's an InputStream type from which we can extract content and relevant information related to the received email like : subject, body, CC, attachments and else.

Let's see how we can extract the content of the email :

## Convert to MimeMessage
We can retrieve content from multipart content-typed message using MimeMessage instance.

```JAVA
public MimeMessage convertToMimeMessage(InputStream data) 
throws MessagingException {
        Session session = Session.getDefaultInstance(new Properties());
        try {
            return new MimeMessage(session, data);
        }catch (MessagingException e){
            throw new MessagingException();
        }
    }
```

## Extract email content
To extract the email content, we'll create an *ReceivedEmail* model to facilitate the processing.
```JAVA
public class ReceivedEmail {

    private String subject;
    private String senderAddress;
    private String senderName;
    private String recipientAddress;
    private String recipientName;
    private String cc;
    private String bcc;
    private String contentType;
    private List<DataSource> attachments = new ArrayList();

    // Getters and setters
    // ...
}
```
For the sake of simplicity I used *String* for recipientAddress, CC and BCC but it's can be a list of addresses (example in the [code](https://github.com/redamessoudi/subethasmtp-springboot)).

We create dedicated service for email content extraction and the extract method could looks like :
```JAVA
public ReceivedEmail extractReceivedEmail(InputStream data) throws Exception {
        ReceivedEmail receivedEmail = new ReceivedEmail();
        MimeMessage message;
        try {
            message = this.convertToMimeMessage(data);
            receivedEmail.setSubject(message.getSubject());
            receivedEmail.setSenderAddress(InternetAddress.toString(message.getFrom()));
            InternetAddress[] recipientAddresses = InternetAddress.parse(InternetAddress.toString(message.getAllRecipients()));
            receivedEmail.setRecipientAddress(InternetAddress.toString(recipientAddresses));
            receivedEmail.setRecipientName(recipientAddresses[0].getPersonal());
            receivedEmail.setContentType(message.getContentType());
            // Use here Apache library for parsing
            MimeMessageParser messageParser = new MimeMessageParser(message);
            messageParser.parse(); // very important to parse before getting data
            receivedEmail.setCc(messageParser.getCc().toString());
            receivedEmail.setBcc(messageParser.getBcc().toString());
            receivedEmail.setAttachments(messageParser.getAttachmentList());
            System.out.println(receivedEmail);
            return receivedEmail;
        } catch (Exception e) {
            throw new Exception();
        }
    }
```
Now we have a full complete email receiver with minimal lines of code.


## Secure SMTP Server

Let's go further step to see how we can secure our mail server.

First thing to do is to indicate that the authentication is required and implement basic auth with username and password.
```JAVA
this.smtpServer = SMTPServer
                .port(25000)
                .simpleMessageListener(marketingMsgListener)
                .requireAuth(true) // auth required
                .authenticationHandlerFactory(easyAuth) // implement type of auth
                .build();
```
Different implementations of *authenticationHandlerFactory* can be done, I chose here, again for the sake of simplicity, the *EasyAuthenticationHandlerFactory* class which needs implementation of the *UsernamePasswordValidator* interface.
```JAVA
@Configuration
public class SimpleAuthValidatorImpl implements UsernamePasswordValidator {

    private final String CREDENTIALS_LOGIN = "superus3r";
    private final String CREDENTIALS_PASSWORD = "passw0rd";

    @Override
    public void login(String username, String password, MessageContext context) throws LoginFailedException {
        if(CREDENTIALS_LOGIN.equals(username) && CREDENTIALS_PASSWORD.equals(password)){
            System.out.println("Authenticated successfully");
        }else{
            System.err.println("Invalid authentication !");
            throw new LoginFailedException();
        }
    }
}
```
And this how our *SMTPServerConfig* looks like :
```JAVA
@Configuration
public class SMTPServerConfig {

    private final SMTPServer smtpServer;
    private final SimpleMessageListener marketingMsgListener;
    private final UsernamePasswordValidator authValidator;
    private final EasyAuthenticationHandlerFactory easyAuth;

    public SMTPServerConfig(SimpleMessageListener marketingMsgListener) {
        authValidator = new SimpleAuthValidatorImpl();
        easyAuth = new EasyAuthenticationHandlerFactory(authValidator);
        this.marketingMsgListener = marketingMsgListener;

        this.smtpServer = SMTPServer
                .port(25000)
                .simpleMessageListener(this.marketingMsgListener)
                .requireAuth(true)
                .authenticationHandlerFactory(easyAuth)
                .build();

        this.smtpServer.start();
    }
}
```

# Go deeper
More parameters can be customised to fit your needs and improve your SubEtha server, I list those below and you can try to explore them to improve your mail receiver implementation :

* Max connections and connection timeout
* TLS support
* Messages size
* Shutdown of the SMTP server
* Testing

# Conclusion
I presented how we can, with small lines of code, write an application that can receive emails, handle those and apply some magic to them with SubEtha SMTP and Spring Boot.

If you have any questions or suggestions, please, leave your comments down below.

Thanks for reading and happy coding.

# Resources
Source code : https://github.com/redamessoudi/subethasmtp-springboot.

Header photo by [Liam Truong](https://unsplash.com/@liamtruong?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/mail?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)