Simple Java Mail Features

Upgrading to 5.0.0? Read the migration notes.

Creating and sending emails is very simple with Simple Java Mail; you don't need to know about the mailing RFC, MimeMessage or any other low level javax.mail API. No anonymous inner classes needed and no large frameworks needed nor XML.

On top of that, Simple Java Mail will do some basic validation checks so that your email is always populated with enough data. It even verifies email addresses against RFC-2822 using the only complete rfc2822 validator in java in the world.

Simple Java Mail also takes care of all the connection and security properties for you.

Roadmap

Currently everything we can think of is included!

Got a suggestion? Please post it in the issue tracker.

§

Basic usage

Simply build an Email, populate it with your data, build a Mailer and send the Email instance. The mailer can be created with your own Session instance as well.

A Mailer instance is reusable.

Email email = EmailBuilder.startingBlank()
    .from("Michel Baker", "m.baker@mbakery.com")
    .to("mom", "jean.baker@hotmail.com")
    .to("dad", "StevenOakly1963@hotmail.com")
    .withSubject("My Bakery is finally open!")
    .withPlainText("Mom, Dad. We did the opening ceremony of our bakery!!!")
    .buildEmail();

MailerBuilder
  .withSMTPServer("server", 25, "username", "password")
  .buildMailer()
  .sendMail(email);
§

About the fluent API with the Builder pattern

The entry classes for the builders are EmailBuilder and MailerBuilder. For both, the first method affects the rest of the builder behavior.

For EmailBuilder, the first method initializes the builder differently, either preconfiguring it (EmailBuilder.copying(), EmailBuilder.replyingTo()), or by setting values otherwise not possible (EmailBuilder.forwarding()).

For MailerBuilder, the first method determines if you get a full builder API or a reduced API because you provided your own custom Session instance.
If you provide your own session, a lot of properties are presumed to be preconfigured, such as SMTP server details.

§

Configure once, reuse many times

You can preconfigure a Mailer and use it many times.

Mailer inhouseMailer = MailerBuilder
    .withSMTPServer("server", 25, "username", "password")
    .buildMailer();

inhouseMailer.sendMail(email);
inhouseMailer.sendMail(anotherEmail);
Or as preconfigured Spring bean:
@Bean
public Mailer inhouseMailer() {{ '{' }}
        return MailerBuilder
            .withSMTPServer(...)
            .buildMailer();
{{ '}' }}
Or the default one from Spring support:

@Import(SimpleJavaMailSpringSupport.class)

@Autowired Mailer mailer; // configured completely using default properties
§

Alternative API for almost everything

Simple Java Mail has alternative ways to do things for almost everything...

For example, when building an email, you can add recipients using Recipient objects, RFC822 compiant String addresses (each can be comma delimited and include optional nested names), InternetAddress objects, collections of said addresses, default address names or fixed address names.

// You can add your own Recipient instances for example
currentEmailBuilder.withRecipients(yourRecipient1, yourRecipient2...);
// or add comma / semicolon separated addresses (without names)
String list = "twister@sweets.com,blue.tongue@sweets.com;honey@sweets.com";
currentEmailBuilder.bcc(list);
// or:
currentEmailBuilder.bccWithDefaultName("maintenance group", list);
currentEmailBuilder.bccWithFixedName("maintenance group", list); // same as .bcc()
// what about a group with one deviating name?
String list = "bob@sweets.com, gene@sweets.com; Security Group <security@sweets.com>";
currentEmailBuilder.toWithDefaultName("stakeholders", list);
// bob and gene are named "stakeholders", "Security Group" get its own name

Through properties:

simplejavamail.defaults.bcc.name=
simplejavamail.defaults.bcc.address=twister@sweets.com,blue.tongue@sweets.com;honey@sweets.com

To give you an idea of how flexible the API is for adding recipients:

// TO
.to(Recipient... recipients)
.to(Collection<Recipient> recipients)
.to(String name, String address)
.to(String oneOrMoreAddresses)
.to(String name, String... oneOrMoreAddressesEach)
.to(String name, Collection<String> oneOrMoreAddressesEach)
.toMultiple(String... oneOrMoreAddressesEach)
.toMultiple(Collection<String> oneOrMoreAddressesEach)
.toWithFixedName(String name, String... oneOrMoreAddressesEach)
.toWithDefaultName(String name, String... oneOrMoreAddressesEach)
.toWithFixedName(String name, Collection<String> oneOrMoreAddressesEach)
.toWithDefaultName(String name, Collection<String> oneOrMoreAddressesEach)
.to(String name, InternetAddress address)
.to(InternetAddress address)
.to(String name, InternetAddress... oneOrMoreAddressesEach)
.toAddresses(String name, Collection<InternetAddress> oneOrMoreAddressesEach)
.toMultiple(InternetAddress... oneOrMoreAddressesEach)
.toMultipleAddresses(Collection<InternetAddress> oneOrMoreAddressesEach)
.toAddressesWithFixedName(String name, InternetAddress... oneOrMoreAddressesEach)
.toAddressesWithDefaultName(String name, InternetAddress... oneOrMoreAddressesEach)
.toAddressesWithFixedName(String name, Collection<InternetAddress> oneOrMoreAddressesEach)
.toAddressesWithDefaultName(String name, Collection<InternetAddress> oneOrMoreAddressesEach)
// CC
.cc(Recipient... recipients)
.cc(Collection<Recipient> recipients)
.cc(String name, String address)
.cc(String oneOrMoreAddresses)
.cc(String name, String... oneOrMoreAddressesEach)
.cc(String name, Collection<String> oneOrMoreAddressesEach)
.ccMultiple(String... oneOrMoreAddressesEach)
.ccAddresses(Collection<String> oneOrMoreAddressesEach)
.ccWithFixedName(String name, String... oneOrMoreAddressesEach)
.ccWithDefaultName(String name, String... oneOrMoreAddressesEach)
.ccWithFixedName(String name, Collection<String> oneOrMoreAddressesEach)
.ccWithDefaultName(String name, Collection<String> oneOrMoreAddressesEach)
.cc(String name, InternetAddress address)
.cc(InternetAddress address)
.cc(String name, InternetAddress... oneOrMoreAddressesEach)
.ccAddresses(String name, Collection<InternetAddress> oneOrMoreAddressesEach)
.ccMultiple(InternetAddress... oneOrMoreAddressesEach)
.ccMultipleAddresses(Collection<InternetAddress> oneOrMoreAddressesEach)
.ccAddressesWithFixedName(String name, InternetAddress... oneOrMoreAddressesEach)
.ccAddressesWithDefaultName(String name, InternetAddress... oneOrMoreAddressesEach)
.ccAddressesWithFixedName(String name, Collection<InternetAddress> oneOrMoreAddressesEach)
.ccAddressesWithDefaultName(String name, Collection<InternetAddress> oneOrMoreAddressesEach)
// BCC
.bcc(Recipient... recipients)
.bcc(Collection<Recipient> recipients)
.bcc(String name, String address)
.bcc(String oneOrMoreAddresses)
.bcc(String name, String... oneOrMoreAddressesEach)
.bcc(String name, Collection<String> oneOrMoreAddressesEach)
.bccMultiple(String... oneOrMoreAddressesEach)
.bccAddresses(Collection<String> oneOrMoreAddressesEach)
.bccWithFixedName(String name, String... oneOrMoreAddressesEach)
.bccWithDefaultName(String name, String... oneOrMoreAddressesEach)
.bccWithFixedName(String name, Collection<String> oneOrMoreAddressesEach)
.bccWithDefaultName(String name, Collection<String> oneOrMoreAddressesEach)
.bcc(String name, InternetAddress address)
.bcc(InternetAddress address)
.bcc(String name, InternetAddress... oneOrMoreAddressesEach)
.bccAddresses(String name, Collection<InternetAddress> oneOrMoreAddressesEach)
.bccMultiple(InternetAddress... oneOrMoreAddressesEach)
.bccMultipleAddresses(Collection<InternetAddress> oneOrMoreAddressesEach)
.bccAddressesWithFixedName(String name, InternetAddress... oneOrMoreAddressesEach)
.bccAddressesWithDefaultName(String name, InternetAddress... oneOrMoreAddressesEach)
.bccAddressesWithFixedName(String name, Collection<InternetAddress> oneOrMoreAddressesEach)
.bccAddressesWithDefaultName(String name, Collection<InternetAddress> oneOrMoreAddressesEach)
// GENERIC
.withRecipientsWithDefaultName(String defaultName, Collection<String> oneOrMoreAddressesEach, RecipientType recipientType)
.withRecipientsWithFixedName(String fixedName, Collection<String> oneOrMoreAddressesEach, RecipientType recipientType)
.withRecipientsWithDefaultName(String name, RecipientType recipientType, String... oneOrMoreAddressesEach)
.withRecipientsWithFixedName(String name, RecipientType recipientType, String... oneOrMoreAddressesEach)
.withRecipients(String name, boolean fixedName, RecipientType recipientType, String... oneOrMoreAddressesEach)
.withRecipients(String name, boolean fixedName, Collection<String> oneOrMoreAddressesEach, RecipientType recipientType)
.withAddressesWithDefaultName(String defaultName, Collection<InternetAddress> addresses, RecipientType recipientType)
.withAddressesWithFixedName(String fixedName, Collection<InternetAddress> addresses, RecipientType recipientType)
.withAddresses(String name, boolean fixedName, Collection<InternetAddress> addresses, RecipientType recipientType)
.withRecipients(Collection<Recipient> recipients)
.withRecipients(Recipient... recipients)
.withRecipients(Collection<Recipient> recipients, RecipientType fixedRecipientType)
.withRecipient(String singleAddress, RecipientType recipientType)
.withRecipient(String name, String singleAddress, RecipientType recipientType)
.withRecipient(Recipient recipient)
§

Asynchronous parallel batch sending

The default mode is to send emails synchronously, blocking execution until the email was processed completely and the STMP server sent a succesful result.

You can also send anyschronously in parallel or batches, or simply send in a fire-and-forget way. If an authenticated proxy is used, the proxy bridging server is kept alive until the last email has been sent.

Depending on the SMTP server (and proxy server if used) this can greatly influence how fast emails are sent.

mailer.sendMail(email, /* async = */ true);

Refer to the configuration section on how to set the thread pool size default.

§

Sending with your own Session instance

If you prefer to use your own preconfigured Session instance and still benefit from Simple Java Mail, you can!

Email email = ...
...

MailerBuilder
    .usingSession(yourSession)
    .buildMailer()
    .sendMail(email);
§

Setting a custom message ID on sent email

Message id's are normally generated by the underlying JavaMail framework, but you can provide your own if required.

Just make sure your own id's conform to the rfc5322 msg-id format standard

currentEmailBuilder.fixingMessageId("<123@456>");
§

Getting the generated email id after sending

Sometimes you need the actual ID used in the MimeMessage that went out to the SMTP server. Luckily, it's very easy to retrieve it.


mailer.sendMail(email); // id updated during sending!
email.getId(); // <1420232606.6.1509560747190@Cypher>
§

Sending with SSL and TLS

Activating SSL or TLS is super easy. Just use the appropriate TransportStrategy enum.

Email email = ...;

MailerBuilder.withTransportStrategy(TransportStrategy.SMTP); // default if omitted
MailerBuilder.withTransportStrategy(TransportStrategy.SMTPS);
MailerBuilder.withTransportStrategy(TransportStrategy.SMTP_TLS);
§

SSL and TLS with Google mail

Here's an example of SSL and TLS using gMail.

If you have two-factor login turned on, you need to generate an application specific password from your Google account.

MailerBuilder
  .withSMTPServer("smtp.gmail.com", 25, "your user", "your password")
  .withTransportStrategy(TransportStrategy.SMTP_TLS)
  // or
  .withSMTPServer("smtp.gmail.com", 587, "your user", "your password")
  .withTransportStrategy(TransportStrategy.SMTP_TLS)
  // or
  .withSMTPServer("smtp.gmail.com", 465, "your user", "your password")
  .withTransportStrategy(TransportStrategy.SMTPS);
§

Adding attachments

You can add attachments very easily, but you'll have to provide the data yourself. Simple Java Mail accepts byte[] and DataSource objects.

currentEmailBuilder
    .withAttachment("dresscode.txt", new ByteArrayDataSource("Black Tie Optional", "text/plain"))
    .withAttachment("location.txt", "On the moon!".getBytes(Charset.defaultCharset()), "text/plain")
    // ofcourse it can be anything: a pdf, doc, image, csv or anything else
    .withAttachment("invitation.pdf", new FileDataSource("invitation_v8.3.pdf"))
§

Embedding images

Embedding images is simple, but you have to add the placeholders in the HTML yourself.

currentEmailBuilder.withEmbeddedImage("smiley", new FileDataSource("smiley.jpg"));
// this example is included in the demo package in MailTestApp.java
String base64String = "iVBORw0KGgoAAAANSUhEUgAAA ...snip";
currentEmailBuilder.withEmbeddedImage("thumbsup", parseBase64Binary(base64String), "image/png");

// the corresponding HTML should contain the placeholders
<p>Let's go!</p><img src='cid:thumbsup'><br/>
<p>Smile!</p><img src='cid:smiley'>
§

Setting custom headers

Sometimes you need extra headers in your email because your email server, recipient server or your email client needs it. Or perhaps you have a proxy or monitoring setup in between mail servers. Whatever the case, adding headers is easy.

currentEmailBuilder
    .withHeader("X-Priority", 2);
    .withHeader("X-MC-GoogleAnalyticsCampaign", "halloween_sale");
    .withHeader("X-MEETUP-RECIP-ID", "71415272");
    .withHeader("X-my-custom-header", "foo");
    // or
    .withHeaders(yourHeadersMap);
§

Setting custom properties on the internal Session

In case you need to modify the internal Session object itself, because you need a tailored configuration that is supported by the underlying javax.mail, that too is very easy.

currentMailerBuilder
    .withProperty("mail.smtp.timeout", 30 * 1000)
    .withProperty("mail.smtp.connectiontimeout", 10 * 1000)
    // or
    .withProperties(yourPropertiesObject)
    .withProperties(yourPropertiesMap)
§

Direct access to the internal Session

For emergencies, you can also get a hold of the internal Session instance itself. You should never need this however and if you do it means Simple Java Mail failed to simplify the configuration process for you. Please let us know how we can help alleviate this need.

Mailer mailer = ...;

Session session = mailer.getSession();
// do your thing with session
§

Signing emails with DKIM

Simple Java Mail also supports signing with DKIM domain keys. It uses java-utils-mail-dkim (dependency packaged along) to perform the DNS DKIM record check on the given domain.

DKIM is an optional feature and if you want to use it, you need to include the following dependency in your project:

<dependency>
    <groupId>net.markenwerk</groupId>
    <artifactId>utils-mail-dkim</artifactId>
    <version>X.X.X</version>
</dependency>
currentEmailBuilder.
    .signWithDomainKey(
       privateKey byte[] / File / InputStream,
       "your_domain.org",
       "your_selector");

mailer.sendMail(signedEmail);
You can also directly use the helper method:
Mailer.signMessageWithDKIM(mimeMessageToSign, emailContainingSigningDetails);
§

Configure delivery / read receipt

For servers and clients that support it (mostly Outlook at offices), Simple Java Mail has built in support for 'delivery receipt' and 'read receipt', which is configured through the headers Return-Receipt-To and Disposition-Notification-To respectively.

You can explicitly define the email address to return the receipts to or else Simple Java Mail will default to the replyTo address if available or else the fromAddress.

currentEmailBuilder.
    .withDispositionNotificationTo();
    .withReturnReceiptTo();
    // or:
    .withDispositionNotificationTo(new Recipient("name", "address@domain.com"));
    .withReturnReceiptTo(new Recipient("name", "address@domain.com"));
§

Validating Email Addresses

Simple Java Mail can validate your email addresses. It's not just a simple regex check, but a complete and robust full validation against RFC-2822. It does this by including email-rfc2822-validator in the library.

Address validation is performed automatically when sending emails, but you can also directly perform validations.

currentMailerBuilder
    .withEmailAddressCriteria(EmailAddressCriteria.RFC_COMPLIANT)
    // or
    .withEmailAddressCriteria(
      of(ALLOW_QUOTED_IDENTIFIERS, ALLOW_PARENS_IN_LOCALPART)
    )
    // or
    .clearEmailAddressCriteria() // turn off validation
    .resetEmailAddressCriteria() // reset to default
// you can also directly perform validations.
mailer.validate(email);

// or use the underlying library included for this
EmailAddressValidator.isValid("your_address@domain.com",
   EmailAddressCriteria.RFC_COMPLIANT);

// or, fine-tuned to be less strict:
EmailAddressValidator.isValid("your_address@domain.com",
   of(ALLOW_QUOTED_IDENTIFIERS, ALLOW_PARENS_IN_LOCALPART));
§

Converting between, Email, MimeMessage, EML and Outlook .msg

With Simple Java Mail you can easily convert to other types.

For example, if you need a MimeMessage, you can convert Email objects, EML data and even Outlook .msg files.

If you already have a MimeMessage, you can it into an Email instance, complete with embedded images and attachments, headers intact.

You can even build a mass Outlook .msg to EML converter if you like!

// from Email
String eml =              EmailConverter.emailToEML(yourEmail);
MimeMessage mimeMessage = EmailConverter.emailToMimeMessage(yourEmail);
MimeMessage mimeMessage = EmailConverter.emailToMimeMessage(yourEmail, yourSession);

// from MimeMessage
Email email =             EmailConverter.mimeMessageToEmail(yourMimeMessage);
String eml =              EmailConverter.mimeMessageToEML(yourMimeMessage);

// from EML
Email email =             EmailConverter.emlToEmail(emlDataString);
MimeMessage mimeMessage = EmailConverter.emlToMimeMessage(emlDataString);
MimeMessage mimeMessage = EmailConverter.emlToMimeMessage(emlDataString, yourSession);

// from Outlook .msg
Email email =             EmailConverter.outlookMsgToEmail(readToString("yourMessage.msg"));
Email email =             EmailConverter.outlookMsgToEmail(new File("yourMessage.msg"));
Email email =             EmailConverter.outlookMsgToEmail(getInputStream("yourMessage.msg"));
String eml =              EmailConverter.outlookMsgToEML(readToString("yourMessage.msg"));
String eml =              EmailConverter.outlookMsgToEML(new File("yourMessage.msg"));
String eml =              EmailConverter.outlookMsgToEML(getInputStream("yourMessage.msg"));
MimeMessage mimeMessage = EmailConverter.outlookMsgToMimeMessage(readToString("yourMessage.msg"));
MimeMessage mimeMessage = EmailConverter.outlookMsgToMimeMessage(new File("yourMessage.msg"));
MimeMessage mimeMessage = EmailConverter.outlookMsgToMimeMessage(getInputStream("yourMessage.msg"));
§

Setting custom recipient for bouncing emails

For bouncing emails, you can provide a hint to the SMTP server to which bouncing emails should be returned. This is also known as the Return-Path or Envelope FROM and is set on the Session instance with the property mail.smtp.from.

Simple Java Mail offers a convenience method to set this property.

// in similar fashion to setting replyTo address:
currentEmailBuilder
    .withBounceTo(aRecipientInstance) // or
    .withBounceTo("Bob", "bob.techdesk@candyshop.com")
    // or using one of the many alternative methods...
§

Replying to and forwarding emails

If you have an email you want to reply to or wish to forward, the EmailBuilder has you covered.


Note: due to the nature of the underlying JavaMail framework (also see reply / forward):

  • In case of replying, the original email is quoted in the body of the reply itself.
  • In case of forwarding, the original email is included as a separate body inside the forward.

Replying to an email:

EmailBuilder
    .replyingTo(receivedEmail) // Email or MimeMessage
    .from("dummy@domain.com")
    .prependText("Reply body. Original email included below")
    .buildEmail();

Forwarding an email:

EmailBuilder
    .forwarding(receivedEmail) // Email or MimeMessage
    .from("dummy@domain.com")
    .text("Hello? This is Forward. See below email:")
    .buildEmail();
§

Send using a proxy

Simple Java Mail supports sending emails through a proxy. It is also the only java mailing framework in the world that supports sending emails through authenticated proxies. The reason for this is that the underlying native Javax Mail framework supports anonymous SOCKS5 proxies, but not authenticated proxies.

To make this work with authentication, Simple Java Mail uses a trick: it sets up a temporary anonymous proxy server for Javax Mail to connect to and then the bridge relays the connection to the target proxy performing the authentication outside of Javax Mail.

This temporary server is referred to as the Proxy Bridging Server.

// anonymous proxy
currentMailerBuilder.withProxy("proxy.host.com", 1080)

// authenticated proxy
currentMailerBuilder.withProxy("proxy.host.com", 1080, "proxy username", "proxy password");

Refer to the configuration section on how to set proxy server defaults and the port on which the proxy bridge runs.

§

Testing a server connection

If you just want to do a connection test using your current configuration, including transport strategy and (authenticated) proxy, Simple Java Mail got you covered.

// configure your mailer
Mailer mailer = ...;

// perform connection test
mailer.testConnection(); // no error means success