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.
Currently everything we can think of is included!
Got a suggestion? Please post it in the issue tracker.
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);
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.
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
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)
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.
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);
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>");
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>
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);
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);
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 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'>
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);
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)
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
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);
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"));
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));
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"));
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...
If you have an email you want to reply to or wish to forward, the EmailBuilder
has you covered.
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();
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.
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