Configuration

Upgrading to 5.0.0? Read the migration notes.

Simple Java Mail provides full configuration through programmatic API as well as system variables, environment variables and properties files (including Spring).

The Java API and config files complement each other. If you provide the overlapping configuration, the programmatic API takes priority, overriding system and environment values, overriding property values.

Central to configuring Simple Java Mail is the MailerBuilder. As the library grew maintaining all the constructors and setters proved unwieldy and so it moved to a completely builder based fluent API which produces a largely immutable Mailer instance.

Second, there is the ConfigLoader, which contains all the preconfigured defaults read initially from .properties files. It contains programmatic API to clear, add or replace default values.

§

Transport strategies

Although Simple Java Mail started out as a library to help produce RFC-anatomically correct emails, one of its primary drivers now is to simplify configuration, using transport strategies.

There are three strategies: TransportStrategy.SMTP, TransportStrategy.SMTPS and TransportStrategy.SMTP_TLS.

Let's quickly review them one-by-one.

§

TransportStrategy.SMTP

This transport strategy falls back to plaintext when a mail server does not indicate support for STARTTLS. Additionally, even if a TLS session is negotiated, server certificates are not validated in any way.


MailerBuilder.withTransportStrategy(TransportStrategy.SMTP);

// or through property defaults, skipping builder API:
simplejavamail.transportstrategy=SMTP
Mailer mailer = MailerBuilder.buildMailer();

Furthermore, this transport strategy only offers protection against passive network eavesdroppers when the mail server indicates support for STARTTLS. Active network attackers can trivially bypass the encryption 1) by tampering with the STARTTLS indicator, 2) by presenting a self-signed certificate, 3) by presenting a certificate issued by an untrusted certificate authority; or 4) by presenting a certificate that was issued by a valid certificate authority to a domain other than the mail server's.

For proper mail transport encryption, use TransportStrategy.SMTPS or TransportStrategy.SMTP_TLS.

To disable opportunistic TLS and revert back to the legacy SMTP_PLAIN behavior prior to 5.0.0 (not recommended), you can turn it off programmatically or by setting the property simplejavamail.opportunistic.tls.


TransportStrategy.SMTP.setOpportunisticTLS(false);
MailerBuilder.withTransportStrategy(TransportStrategy.SMTP);
// or as property:
simplejavamail.opportunistic.tls=false
§

TransportStrategy.SMTPS

SMTP entirely encapsulated by TLS. Commonly known as SMTPS.

Strict validation of server certificates is enabled. Server certificates must be issued
1) by a certificate authority in the system trust store; and
2) to a subject matching the identity of the remote SMTP server.


MailerBuilder.withTransportStrategy(TransportStrategy.SMTPS);

// or through property defaults, skipping builder API:
simplejavamail.transportstrategy=SMTPS
Mailer mailer = MailerBuilder.buildMailer();
§

TransportStrategy.SMTP_TLS

Plaintext SMTP with a mandatory, authenticated STARTTLS upgrade.

Strict validation of server certificates is enabled. Server certificates must be issued
1) by a certificate authority in the system trust store; and
2) to a subject matching the identity of the remote SMTP server.


MailerBuilder.withTransportStrategy(TransportStrategy.SMTP_TLS);

// or through property defaults, skipping builder API:
simplejavamail.transportstrategy=SMTP_TLS
Mailer mailer = MailerBuilder.buildMailer();

To quote FastMail on the differences between SSL and TLS:

SSL and TLS both provide a way to encrypt a communication channel between two computers (e.g. your computer and our server). TLS is the successor to SSL and the terms SSL and TLS are used interchangeably unless you're referring to a specific version of the protocol.

The ordering of protocols in terms of oldest to newest is: SSL v2, SSL v3, TLS v1.0, TLS v1.1, TLS v1.2, TLS v1.3 (currently proposed).

§

Programmatic API - common settings

Everything can be configured through the java API. Specifically the builders are the entry point to creating Mailers and Emails and everything can be configured through them.

// start with a builder
MailerBuilder.withSMTPServer("smtp.host.com", 25, "username", "password");
// or
MailerBuilder
  .withSMTPServerHost("smtp.host.com")
  .withSMTPServerPort(25)
  .withSMTPUsername("username")
  .withSMTPPassword("password");

// you can even leave out some details for an anonymous SMTP server
MailerBuilder.withSMTPServer("smtp.host.com", 25);
// or
MailerBuilder
  .withSMTPServerHost("smtp.host.com")
  .withSMTPServerPort(25);

// adding the transport strategy...
currentMailerBuilder.withTransportStrategy(TransportStrategy.SMTP_TLS)

// or instead adding anonymous proxy configuration
currentMailerBuilder.withProxy("proxy.host.com", 1080);
// or
currentMailerBuilder
  .withProxyHost("smtp.host.com")
  .withProxyPort(25);

// or authenticated proxy
currentMailerBuilder
  .withProxy("proxy.host.com", 1080, "proxy username", "proxy password");
// or
currentMailerBuilder
  .withProxyHost("smtp.host.com")
  .withProxyPort(25)
  .withProxyUsername(25)
  .withProxyPassword(25);

// anonymous smtp + anonymous proxy + default SMTP protocol strategy
currentMailerBuilder
        .withSMTPHost("smtp.host.com").withSMTPServerPort(25)
        .withProxyHost("proxy.host.com").withSMTPPort(1080);

// configure everything!
MailerBuilder
        .withSMTPHost("smtp.host.com", 587, "user@host.com", "password")
        .withTransportStrategy(TransportStrategy.SMTP_TLS);
        .withProxyHost("socksproxy.host.com", 1080, "proxy user", "proxy password");
        .buildMailer()
        .sendMail(email);

// preconfigured Session?
MailerBuilder.usingSession(session);

// preconfigured but you need anonymous proxy?
MailerBuilder
        .usingSession(session)
        .withProxyHost("socksproxy.host.com", 1080);

// preconfigured but you need authenticated proxy?
MailerBuilder
        .usingSession(session)
        .withProxyHost("socksproxy.host.com", 1080, "proxy user", "proxy password");
§

Programmatic API - other settings

Aside from transport strategy, SMTP and Proxy server details, there are a few other more generic settings.

// make the underlying javax.mail produce more logging
MailerBuilder.withDebugLogging(true);
// skip actually sending email, just log it
currentMailerBuilder.withTransportModeLoggingOnly(true);

// change email validation strategy
currentMailerBuilder.withEmailAddressCriteria(EmailAddressCriteria.DEFAULT);
currentMailerBuilder.withEmailAddressCriteria(EmailAddressCriteria.RFC_COMPLIANT);
currentMailerBuilder.withEmailAddressCriteria(EnumSet
       .of(ALLOW_QUOTED_IDENTIFIERS, ALLOW_PARENS_IN_LOCALPART));

// reset to default RFC compliant checks:
currentMailerBuilder.resetmailAddressCriteria();
// deactivate email validation completely:
currentMailerBuilder.clearEmailAddressCriteria();

// change SOCKS5 bridge port in case of authenticated proxy
currentMailerBuilder.withProxyBridgePort(1081); // always localhost

// set custom properties
currentMailerBuilder.withProperties(new Properties());
currentMailerBuilder.withProperties(new HashMap());
currentMailerBuilder.withProperty("mail.smtp.sendpartial", true);

// or directly modify the internal Session instance:
mailer.getSession().getProperties().setProperty("mail.smtp.sendpartial", true);

// trust all hosts for SSL connections, don't validate keys
currentMailerBuilder.trustingAllSSLHosts(true);

// white list hosts for SSL connections, don't validate keys for these
currentMailerBuilder.trustingSSLHosts("a", "b", "c", ...);
// or clearing them
currentMailerBuilder.clearTrustedSSLHosts();
// change the pool size (default 10) for concurrent threads, each sending an email
currentMailerBuilder.withThreadPoolSize(3);
// change the session timeout (affects socket connect-, read- and write timeouts)
currentMailerBuilder.withSessionTimeout(10 * 1000); // 10 seconds for quick disconnect
§

Properties files

With properties files you can define defaults and overrides. You can also provide overriding value by defining system variables.

Simple Java Mail will automatically load properties from simplejavamail.properties, if available on the classpath. Alternatively, you can manually load additional properties files in a number of ways.

Properties are loaded in order of priority from high to low:

  1. Programmatic values
  2. System variables
  3. Environment variables
  4. Properties from config files
ConfigLoader.loadProperties("overrides-on-classpath.properties", /* addProperties = */ true);
ConfigLoader.loadProperties(new File("d:/replace-from-environment.properties"), /* addProperties = */ false);
ConfigLoader.loadProperties(usingMyOwnInputStream, addProperties);
ConfigLoader.loadProperties(usingMyOwnPropertiesObject, addProperties);
This clears everything:
ConfigLoader.loadProperties(new Properties(), /* addProperties = */ false);
§

Available properties

Almost everything can be set as a default property. This way you can easily configure environments without changing the code.

simplejavamail.javaxmail.debug=true
simplejavamail.transportstrategy=SMTPS
simplejavamail.smtp.host=smtp.default.com
simplejavamail.smtp.port=25
simplejavamail.smtp.username=username
simplejavamail.smtp.password=password
simplejavamail.proxy.host=proxy.default.com
simplejavamail.proxy.port=1080
simplejavamail.proxy.username=username proxy
simplejavamail.proxy.password=password proxy
simplejavamail.proxy.socks5bridge.port=1081
simplejavamail.defaults.subject=Sweet News
simplejavamail.defaults.from.name=From Default
simplejavamail.defaults.from.address=from@default.com
simplejavamail.defaults.replyto.name=Reply-To Default
simplejavamail.defaults.replyto.address=reply-to@default.com
simplejavamail.defaults.to.name=To Default
simplejavamail.defaults.to.address=to@default.com
simplejavamail.defaults.cc.name=CC Default
simplejavamail.defaults.cc.address=cc@default.com
simplejavamail.defaults.bcc.name=
simplejavamail.defaults.bcc.address=bcc1@default.com;bcc2@default.com
simplejavamail.defaults.poolsize=10
simplejavamail.defaults.sessiontimeoutmillis=60000
simplejavamail.transport.mode.logging.only=true
simplejavamail.opportunistic.tls=false
§

Combining both for multiple environments

Let's set up configuration for a test, acceptance and production environment.

Properties for the environments

#global default properties (simplejavamail.properties on classpath)

    # anonoymous SMTP inside 'safe' DMZ
    simplejavamail.smtp.host=dmz.smtp.candyshop.com
    simplejavamail.smtp.port=25

    # default sender and reply-to address
    simplejavamail.defaults.from.name=The Candy App
    simplejavamail.defaults.from.address=candyapp@candystore.com
    simplejavamail.defaults.replyto.name=Candystore Helpdesk
    simplejavamail.defaults.replyto.address=helpdesk@candystore.com
#overrides from TEST and UAT .../config/candystore/simplejavamail.properties

    # always send a copy to test archive
    simplejavamail.defaults.bcc.name=Archive TST UAT
    simplejavamail.defaults.bcc.address=test-archive@candyshop.com
#overrides from PRODUCTION .../config/candystore/simplejavamail.properties

    # always send a copy to production archive
    simplejavamail.defaults.bcc.name=Archive PRODUCTION
    simplejavamail.defaults.bcc.address=prod-archive@candyshop.com

    # smtp server in production is protected
    simplejavamail.smtp.username=creamcake
    simplejavamail.smtp.password=crusty_l0llyp0p

    # sending mails in production must go through proxy
    simplejavamail.proxy.host=proxy.candyshop.com
    simplejavamail.proxy.port=1080
    simplejavamail.proxy.username=candyman
    simplejavamail.proxy.password=I has the sugarcanes!!1!

Now for the programmatic part

// simplejavamail.properties is automatically loaded

// assume that every environment provides its own property file
ConfigLoader.loadProperties(new File(".../config/candystore/simplejavamail.properties"));

// see if we need to do some specific override for some reason
if (someSpecialCondition) {{ '{' }}
  ConfigLoader.loadProperties("special-override.properties", true);
{{ '}' }}

// or maybe we want to ditch all defaults and trust someone else's config completely
if (ditchOwnAndTrustOtherSource) {{ '{' }}
  ConfigLoader.loadProperties(someFileOrInputSource, false);
{{ '}' }}

// maybe the config service has something?
ConfigLoader.loadProperties(socket.getInpuStream(), true);
// or you have your own Properties source?
ConfigLoader.loadProperties(myOwnProperties, true);

Maybe we want to connect slightly different for some reason:

// override only the port and connection type, leave everything else to config files
Mailer mailer = MailerBuilder
                  .withSMTPPort(587)
                  .withTransportStrategy(TransportStrategy.SMTP_TLS)
                  .buildMailer();
§

Spring support

Everything can be configured through Spring properties, allowing for robust profile-based configuration.

By importing the Spring support bean from Simple Java Mail, whatever properties are provided through Spring are then transfered to Simple Java Mail using the ConfigLoader. It will add or overwrite whatever properties have been loaded before that (including the regular simplejavamail.properties).

Here's a sample configuration using Java style configuration.

Loading Spring support and obtaining default Mailer instance:
@Component // or @Configuration etc.
@Import(SimpleJavaMailSpringSupport.class)
public class YourEmailService {{ '{' }}

    @Autowired // or roll your own, as long as SimpleJavaMailSpringSupport is processed first
    private Mailer mailer;

{{ '}' }}
Then when you have profile based configuration (for example default and production):
#application.properties
simplejavamail.javaxmail.debug=true
simplejavamail.smtp.host=smtp.host
simplejavamail.smtp.port=25
simplejavamail.transportstrategy=SMTP
#application-production.properties
simplejavamail.javaxmail.debug=false
simplejavamail.smtp.host=smtp.production.host
simplejavamail.smtp.port=443
simplejavamail.transportstrategy=SMTPS
simplejavamail.smtp.username=<username>
simplejavamail.smtp.password=<password>
simplejavamail.proxy.username=<proxy_username>
simplejavamail.proxy.password=<proxy_password>