Fork me on GitHub
Simple Java Mail
Simple API, Complex Emails

Simple Java Mail Features

(also check the configuration section if you're missing a feature)

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.

Entry classes

The primary entry classes are EmailBuilder and MailerBuilder. Other entry classes are EmailConverter and JMail (the latter as alternative to using the validation methods on the Mailer instance). Finally, MailerHelper exposes some utilities in case you don't actually need to connect to a server.

Default features

Simple Java Mail will do some basic validation checks so that your email is always populated with enough data. It also checks for CRLF injection attacks. It even verifies email addresses against RFC-2822 and others using JMail. Simple Java Mail also takes care of all the connection and security properties for you.

Builders all the way down

With all the possible ways to configure Email and Mailer instances, the library had only one option left to streamline API, avoid the Telescoping Constructor anti-pattern and keep things manageable: fluent builders.

  1. With fluent builders, we can tightly control valid combinations, logical decision paths and easily provide alternative methods.
  2. At the same time we can concentrate all mutation logic in the builders and produce mostly immutable objects.
  3. Finally, we're able to centralize our documentation around the builders and refer to it from wherever this library is used.


Currently everything we can think of is included or on the issue tracker!

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", "")
    .to("mom", "")
    .to("dad", "")
    .withSubject("My Bakery is finally open!")
    .withPlainText("Mom, Dad. We did the opening ceremony of our bakery!!!")

  .withSMTPServer("server", 25, "username", "password")

About the fluent API with the Builder pattern

The entry classes for the builders are EmailBuilder and MailerBuilder.

For EmailBuilder, the first method initializes the builder in different ways, leaving it with defaults (EmailBuilder.startingBlank(), 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. It is thread-safe.

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

Or as preconfigured Spring bean:
public Mailer inhouseMailer() {
    return MailerBuilder
Or the default one from the Spring support module:


@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 = ",;";
// or:
currentEmailBuilder.bccWithDefaultName("maintenance group", list);
currentEmailBuilder.bccWithFixedName("maintenance group", list); // same as .bcc()
// what about a group with one deviating name?
String list = ",; Security Group <>";
currentEmailBuilder.toWithDefaultName("stakeholders", list);
// bob and gene are named "stakeholders", "Security Group" get its own name

Through properties:,;

To give you an idea of how flexible the API is for just 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)
.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 and clustering

The default mode is to send emails synchronously, blocking execution until the email was processed completely and the STMP server sent a successful 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);
Or configure it when building the mailer:

Mailer mailer = mailerBuilder


Refer to the configuration section on how to set the thread pool size default or how to configure the executor service (thread pool manager).

Advanced batch processing
You can maximize performance by including the batch-module, which allows you to pool the (Transport) connection over multiple sends, which generally saves 50% time for simpler emails). Going further, you can allow for multiple pooled connections to the same server and further still: even cluster multiple pools of connections to different servers!

Refer to the configuration section for details.


Handling asynchronous mailing result

To handle the successful or erroneous result of an async sent email, you can just register your handlers on the returned CompletableFuture.

Also read this excellent primer on how to process exceptions with CompletableFuture.

Note that non-async sending or testing connections return a CompletableFuture that is completed immediately.

CompletableFuture<Void> f = mailer.sendMail(email, true);
// also mailer.testConnection(email, true)
// or mailerBuilder.async() and then just mailer.sendMail(email)

// one of the many ways you can handle the result:
	.whenComplete((result, ex) -> {
		if (ex != null) {
			System.err.printf("Execution failed %s", ex);
		} else {
			System.err.printf("Execution completed: %s", result);

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 = ...


Setting a custom message ID on sent email

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

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


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

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.

  .withSMTPServer("", 25, "your user", "your password")
  // or
  .withSMTPServer("", 587, "your user", "your password")
  // or
  .withSMTPServer("", 465, "your user", "your password")

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.

    .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 dead simple with two options:

  1. manual embedding: add cid: placeholders in the HTML yourself
  2. auto resolution: enable auto-resolving image sources to files, class path resources or URL's

Manual embedding:

currentEmailBuilder.withEmbeddedImage("smiley", new FileDataSource("smiley.jpg"));
currentEmailBuilder.withEmbeddedImage("thumbsup", parseBase64Binary(base64String), "image/png");
// above example is included in the demo package in

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

Auto resolution can be enabled for files, classpath resources and URL's and you can configure base dirs and optionally enforce that referenced resources should all be resolved successfully. Useful for when you allow end users to freely enter HTML.

Auto resolution:

<p>Let's go!</p><img src='smiley.jpg'><br/>
<p>Smile!</p><img src=''>

// results in the following HTML when building the email:
<p>Let's go!</p><img src='cid:etweffxdeu'><br/>
<p>Smile!</p><img src='cid:sienfddiew'>

email.getEmbeddedImages(); // now contains two data sources!

To enable this:

	// enable auto resolution
	.withEmbeddedImageAutoResolutionForFiles(true) // default false
	.withEmbeddedImageAutoResolutionForClassPathResources(true) // default false
	.withEmbeddedImageAutoResolutionForURLs(true) // default false

	// support for base dirs
	.withEmbeddedImageBaseDir(RESOURCES_PATH + "/images")

	// allow resources outside of basedir (careful, potential security attack surface!)
	.allowingEmbeddedImageOutsideBaseDir(true) // default false
	.allowingEmbeddedImageOutsideBaseClassPath(true) // default false
	.allowingEmbeddedImageOutsideBaseUrl(true) // default false

	// fail if a resource couldn't be resolved
	.embeddedImageAutoResolutionMustBeSuccesful(true) // default false (lenient mode)
Also works with properties:

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.

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

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.

    .withProperty("mail.smtp.timeout", 30 * 1000)
    .withProperty("mail.smtp.connectiontimeout", 10 * 1000)
    // or

You can also set some default properties to automatically be added.

Every property prepended with simplejavamail.extraproperties will be loaded directly on the internal Session object.

Sending a Calendar event (iCalendar vEvent)

You want to send a nice Calendar event (.ics) that a client such as Outlook processes nicely?


Produce a Calendar event String (manually or by using a library such as ical4j) and pass it to the EmailBuilder.

See the test demo app included in the Simple Java Mail source for a working example.

// Create a Calendar with something like ical4j
Calendar icsCalendar = new Calendar();
icsCalendar.getProperties().add(new ProdId("-//Events Calendar//iCal4j 1.0//EN"));

(..) // add attendees, organizer, end/start date and whatever else you need

// Produce calendar string
ByteArrayOutputStream bOutStream = new ByteArrayOutputStream();
new CalendarOutputter().output(icsCalendar, bOutStream);
String yourICalEventString = bOutStream.toString("UTF-8")

// Let Simple Java Mail handle the rest
    .withCalendarText(CalendarMethod.REQUEST, yourICalEventString)

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 the dkim-module module to perform the DNS DKIM record check on the given domain.

       privateKey byte[] / File / InputStream,

You can also directly use the helper method:
MailerHelper.signMessageWithDKIM(mimeMessageToSign, emailContainingSigningDetails);

Signing / encrypting emails with S/MIME

Simple Java Mail supports signing and encrypting with S/MIME. It uses the smime-module module to perform the signing / encryption.

You can sign, encrypt or both sign and encrypt an email. In the latter case the email will first be signed and then encrypted, as per advice of the underlying library. All signing/encrypting is performed when the email is being sent.

You can sign individual emails or sign all emails by configuring S/MIME on the Mailer instead.

Signing an email:
Pkcs12Config myKeyInfo = Pkcs12Config.builder()

Email emailToBeSigned = currentEmailBuilder.

Encrypting an email:
Email emailToBeEncrypted = currentEmailBuilder.

Sign all emails by default:
Or with properties:
# defaults on Mailer level:
# encryption can only be applied to individual Email instances
# but this can be default behaviour (not recommended as users would need to share private keys)

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.

    // or:
    .withDispositionNotificationTo(new Recipient("name", ""));
    .withReturnReceiptTo(new Recipient("name", ""));

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 and others. It does this by including JMail in the library.

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

See JMail for more examples and configurations.

    		.withRule(email -> email.localPart().startsWith("allowed"))
    // or
    .clearEmailValidator() // turn off validation
    .resetEmailValidator() // reset to default (strict)
// you can also directly perform validations:
mailer.validate(email); // does all checks including address validation

// or just do the address validation

// or, fine-tuned to be stricter

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

With Simple Java Mail you can easily convert between email types. This includes reading S/MIME protected emails from file.

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 convert it into an Email instance, complete with embedded images and attachments (or just the metadata), headers intact.

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

To enable Outlook message parsing support, include the outlook-module. To enable S/MIME signed content and decryption support, include the smime-module

 * Most conversion methods support an optional Pkcs12Config config for handling S/MIME

// 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"));

Pkcs12Config myKeyInfo = Pkcs12Config.builder()

Email decryptedEmail =    EmailConverter.emlToEmail(emlDataString, myKeyInfo);

Reading S/MIME signed / encrypted attachments

Simple Java Mail can automatically handle S/MIME signed messages or attachments and has some useful extras such as providing you with metadata.

S/MIME is an optional feature and if you want to use it, you need to include the smime-module.

Email mergedEmail = EmailConverter.outlookMsgToEmail("yourSMIMESignedMessage.msg"); // or
Email mergedEmail = EmailConverter.emlToEmail("yourSMIMESignedMessage.eml");

// all attachments as-is:
mergedEmail.getAttachments(); // smime.p7m, my-doc.docx
// all attachments with the encrypted ones replaced:
mergedEmail.getDecryptedAttachments(); // signed-email.eml, my-doc.docx

// if the message itself was signed (rather than a independently signed attachment):
OriginalSmimeDetails details = mergedEmail.getOriginalSmimeDetails();
details.getSmimeMode(); // SIGNED
details.getSmimeMime(); // application/pkcs7-mime or multipart/signed
details.getSmimeType(); // signed-data, enveloped-data
details.getSmimeName(); // smime.p7m or smime.p7s
details.getSmimeMicalg(); // ie. sha-512
details.getSmimeSignedBy(); // email or name used

S/MIME signed messages are merged by default

As an S/MIME signed message is actually nested as an attachment, the default behavior is to merge the S/MIME signed content into the root message. This only happens if there was exactly one S/MIME signed attachment and the decrypted version is of type "message/rfc822".

This default behavior can be deactivated. For your convenience, the decrypted message is available as a separate Email instance:

Email nonMergedEmail = EmailBuilder

// or by configuring the intermediary builder:
emailBuilder = EmailConverter.outlookMsgToEmailBuilder(msgFile); // or
emailBuilder = EmailConverter.emlToEmailBuilder(emlFile);
Email nonMergedEmail = emailBuilder
You always have access to the nested decrypted message:

If a message is both signed and encrypted, getSmimeSignedEmail() will itself have a nested getOriginalSmimeDetails().

        signedAndEncrypted.getOriginalSmimeDetails().smimeMode(); // SIGNED_ENCRYPTED
        Email signedOrEncrypted = signedAndEncrypted.getSmimeSignedEmail();

        signedOrEncrypted.getOriginalSmimeDetails().smimeMode(); // SIGNED or ENCRYPTED

        // whether it is SIGNED or ENCRYPTED depends on the order in which the original
        // email client handled this S/MIME scenario

Decrypting S/MIME attachments using certificate

Every conversion method optionally accepts a Pkcs12Config instance, which contains details about your key store and certificate. With that, you can decrypt an S/MIME encrypted mail.

Pkcs12Config yourPkcs12Config = Pkcs12Config.builder()
      .pkcs12Store("smime_keystore.pkcs12") // path, File or InputStream

EmailConverter.outlookMsgToEmail("yourSMIMEEncryptedMessage.msg", yourPkcs12Config); // or
EmailConverter.emlToEmail("yourSMIMEEncryptedMessage.eml", yourPkcs12Config);

mergedEmail.getOriginalSmimeDetails().getSmimeMode(); // ENCRYPTED or SIGNED_ENCRYPTED

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:
    .withBounceTo(aRecipientInstance) // or
    .withBounceTo("Bob", "")
    // 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 Jakarta Mail 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:

    .replyingTo(receivedEmail) // Email or MimeMessage
    .prependText("Reply body. Original email included below")

Forwarding an email:

    .forwarding(receivedEmail) // Email or MimeMessage
    .text("Hello? This is Forward. See below email:")

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 Jakarta 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("", 1080)

// authenticated proxy
currentMailerBuilder.withProxy("", 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.

The connection test can also be done asynchronously and the result can be handled asynchronously as well. Take a look at Handling asynchronous mailing result.

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

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

Serializing Email objects

Simple Java Mail supports native Java serialization for Email objects with the following caveats:

  • AttachmentResource.dataSource of type DataSource is transient
  • Email.emailToForward of type MimeMessage is transient
  • Email.dkimPrivateKeyInputStream of type InputStream is transient
  • Email.pkcs12ConfigForSmimeSigning of type Pkcs12Config is transient

Plug your own sending logic

You want to benefit from Simple Java Mail's powerful features, but want to replace the actual server testing and email sending with your own?
Simple Java Mail's got your back.

Send mail using MailGun REST API:

Mailer mailGunMailer = MailerBuilder
      .withCustomMailer(new MailGunMailer())
public class MailGunMailer implements CustomMailer {

	public void testConnection(OperationalConfig operationalConfig, Session session) {
		// call MailGun rest service to test the provided config

	public void sendMessage(OperationalConfig operationalConfig, Session session, Email email, MimeMessage message) {
		// call MailGun rest service to send the email!