Lightweight SMTP connection pool with clustering support, wait/release mechanism, connection lifecycle management, eager/lazy loading pool with load balancing and auto-expiry policy support
smtp-connection-pool is an ultra lightweight SMTP connection pool with clustering support, claim/wait/release mechanism,
connection lifecycle management, eager/lazy loading pool with auto-expiry policy support.
This library does not take care of creating or sending emails; it just pools (hot) reusable Transport instances using Session
instances provided by the user.
This SMTP connection pool is used by Simple Java Mail, which offers a complete solution to creating, converting and sending emails.
This library aims to improve performance for sending emails using Java Mail (now Jakarta Mail).
It represents three improvements over usual manual Session.getTransport().connect()
approach:
This library builds on top of clustered-object-pool.
Note: This library doesn’t configure mail Session
instances itself: it only manages the connection you can make with them.
This library leaves it up to the user on how the connection behaves (to which server, proxy, SSL, TLS, session / connection timeouts etc).
Simple Java Mail offers a complete solution for sending emails (which uses SMTP Connection Pool).
There are a couple of scenario’s you can solve with clustered-object-pool:
To keep API simple, this library provides both a simple Connection Pool class as well as a Clustered Connection Pool class. The only difference is in the generics for key-types they pass on to the
superclass.
A very common scenario is to have a single connection being reused over many email-sending threads and usually this is enough. This can be achieved by having 1 cluster with 1 pool of
size 1. This already gives a real boost over not using a connection pool, since threads using the same transport but each establishing a new connection each takes half of the time of sending the
email itself.
The next solution satisfies most performance needs by far: having 1 cluster with 1 pool, but multiple connections. This takes the above approach to the next level by allowing multiple concurrent
connections to your mail server. If your server can handle it, you really scale up on performance. Try benchmarking your server with test emails with different pool sizes to see when performance
starts to degrade.
Finally, the next solution satisfies if you really need to send a lot of emails in a reasonable time. Define a cluster of several mail servers to which you can have one or multiple concurrent
connections. You rarely need this kind of performance, but sending news letters or world wide updates become can benefit greatly from this.
<dependency>
<groupId>org.simplejavamail</groupId>
<artifactId>smtp-connection-pool</artifactId>
<version>2.3.4</version>
</dependency>
// Simple on-demand (lazy loading) connection pool with default size of 4,
// where the connections remain open until the pool is shut down.
SmtpConnectionPool pool = new SmtpConnectionPool(new SmtpClusterConfig());
PoolableObject<SessionTransport> poolableTransport = pool.claimResourceFromCluster(session);
// ... send the email
poolableTransport.release(); // make available in the connection pool again
The pool looks like a cluster and you still claim connections from a cluster, but for each server (backed by a Session) a new cluster is defined under the hood so effectively nothing is
clustered.
Let’s see what options we have:
SmtpClusterConfig smtpClusterConfig = new SmtpClusterConfig();
smtpClusterConfig.getConfigBuilder()
.allocatorFactory(new MyCustomTransportAllocatorFactory())
.defaultCorePoolSize(10) // eagerly start making up to 10 SMTP connections
.defaultMaxPoolSize(10) // maximum pool size, after which claims become blocking
// default is never-expire, this one closes connections randomly between 5 to 10 seconds after last use
.defaultExpirationPolicy(new SpreadedTimeoutSinceLastAllocationExpirationPolicy<Transport>(5, 10, SECONDS))
.cyclingStrategy(new RandomAccessCyclingStrategy()) // default is round-robin
.claimTimeout(new Timeout(30, SECONDS)); // wait for available connection until max 30 seconds, default is indefinitely
SmtpConnectionPoolClustered pool = new SmtpConnectionPoolClustered(smtpClusterConfig);
New clusters and pools are created on-demand with the global defaults, based on cluster keys (for example a UUID) and pool keys (Session instances) passed to the claim invocations. You can however…
// continuing the above code example...
UUID keyCluster1 = UUID.randomUUID();
UUID keyCluster2 = UUID.randomUUID();
Session sessionServerA = ...;
Session sessionServerB = ...;
// define different behavior only for server A in cluster 1
pool.registerResourcePool(new ResourceClusterAndPoolKey<>(keyCluster1, sessionServerA),
new TimeoutSinceCreationExpirationPolicy<Transport>(30, SECONDS),
4, // core pool size of eagerly opened and available connections
10); // max pool size
Since acquiring SMTP Transport instances works a little differently when using OAuth2, you need to supply your OAuth2 token in the Session under a predefined property:
session.getProperties().setProperty(SmtpConnectionPool.OAUTH2_TOKEN_PROPERTY, yourOAuth2Token);