Skip to main content

How and why I designed an email library

 Greetings!

How do you send emails using Java? You would probably use a free library/framework like Spring or anything available. Or, you might write a simple email-sending class. However, when I needed an emailing functionality for one of the requirements, I decided to do more.

Why?

In larger projects, we always should think about the bigger picture.
  • Adding a new library should be done with a lot of investigation
  • Module-only features have no value for the product
That is why I thought to give this an extra effort and designed an internal email library.

General idea

This is simple. Any team should be able to use this library without depending on any other external libraries. Also, the email API can have any implementation without impacting consumer modules.

Existing libraries

Initially, I thought to use Spring email but Spring core doesn't come with it. It looks like Spring should have separate jars for this. But anyway this will not help me now. There are other email libraries but due to legacy reasons, it is not an immediate option.

What features do we prefer?

What is important for this article is the main ideas behind the decision instead of creating a simpler class.
  • Should be reusable across multiple modules
  • The consumer should only depend on the API
  • Implementation should be independently deployable
  • Consumer modules should not depend on the implementation
  • Implementation should be expandable in the future without affecting any consumers
  • Implementation should be replaceable with an open-source library when needed
  • Configuration properties should be loaded without restarting the server

Let's design

I had this idea of an email where the consumer should not know anything regarding the implementation.
Email email = Email.builder().from().to().subject().body().attachments().build();
emailSender.send(email);
Consumers should not know any details about the implementation. Also, I should be able to change the implementation (say I switch it to open source library) without impacting the consumers.

Design - API

The most important thing here for me is the API. I wanted to give a flexible, easy-to-use API as above. Hence I created Email as a builder and provided a simple interface to use.
public interface EmailSender {
  void send(Email email);
}

public class Email {
  private String from;
  private List<String> to;
  private String subject;
  private String message;
  
  // getter
  
  public static class Builder {
	// standard builder implementation
  }
}
I have a few more classes (headers, attachments, etc) but this is the core. If you don't like a builder, you can use a step chain.

Design - API implementation

API and API implementations are separated. This is something related to our module system as the API consumers should not depend on the implementation of the build time. Well, this perfectly aligned with the modularity as well.
What I did here is, create a wrapper around Java's email API so that we can replace it with any open-source library in the future. (unable to share the code)
public class SimpleEmailSender implements EmailSender {
  
  public void send(Email email) {
    // do not use Java email MimeMessage directly here, 
    // instead wrap it so that this implementation is isolated.
  }

}

Future

Anyone who likes this can create a spring-boot-starter with this API. I really like to do that but currently do not have time. In my opinion, simple API is missing in Spring email so that consumers can compose an email like the above. (However, there are other libraries that do like that)

Note:- Only the main ideas are shared.

Happy coding guys ☺

Comments