SMTP NIO
A Java library that supports Non-blocking I/O (NIO) Simple Mail Transfer Protocol (SMTP) operations.
The SMTP NIO client provides a framework to interact with SMTP servers and send messages asynchronously using a non-blocking I/O mechanism. This grants great efficiency, flexibility and scalability for clients especially intended to handle large amounts of traffic.
Table of Contents
Background
Java's current built-in API, JavaMail is limited to blocking operations on server interactions. This can especially be inconvenient as threads block while waiting for requests to finish. This framework is designed to use asynchronous, non-blocking operations to perform transactions so threads do not need to wait upon making a request. This design improves thread utilization and provides an overall performance improvement.
Some of the more distinguishing features of this library are:
- Highly customizable thread model and server/client idle max limit
- Leverages the well-established framework Netty
- Future-based design enables a clean separation of the SMTP client threads pool and the consumers threads pool
- Simple Mail Transfer Protocol (SMTP) support RFC 5321
- SMTPS and StartTls support RFC 3207
- HELO command support RFC 821 (Section 3.5)
- EHLO command support RFC 1869 (Section 4)
- AUTH command support RFC 4954
- QUIT command support RFC 5321 (Section 4.1.1.10)
This project is ideal for applications that have a high requirement to optimize thread utilization and improve overall resource capacity. Specifically, this is best for situations where users need to perform extensive communications the SMTP servers.
Install
This library is built and managed using maven. Update your project's pom.xml file to include the follow dependency:
<dependency>
<groupId>com.yahoo.smtpnio</groupId>
<artifactId>smtpnio.core</artifactId>
<version>1.1.5</version>
</dependency>
Install the framework via:
$ mvn clean install
For contributors run deploy to do a push to nexus servers:
$ mvn clean deploy -Dgpg.passphrase=[passPhrase]
Usage
The following code snippets demonstrate the basic functionality of creating a session with a SMTP server, issuing a command, and retrieving the response.
Create a client with a desired number of threads
final int numOfThreads = 4;
final SmtpAsyncClient smtpClient = new SmtpAsyncClient(numOfThreads);
Establish a SMTP server connection and create a session
// Use SSL?
final boolean enableSsl = true;
// This example defines a connection to smtp.example.com through port 465 over SSL
final SmtpAsyncSessionData sessionData = SmtpAsyncSessionData.newBuilder("smtp.example.com", 465, enableSsl)
.setSessionContext("client007") // optional parameter used as an ID for debugging purposes
.setSniNames(null) // optional list of SNI names
.setLocalAddress(null); // optional local address if present
.build();
// Session configurations such as timeouts
final SmtpAsyncSessionConfig sessionConfig = new SmtpAsyncSessionConfig()
.setConnectionTimeout(5000)
.setReadTimeout(7000)
.setEnableStarttls(true); // enable startTls option which is false by default
// Asynchronous call to create a Future containing the session data
final Future<SmtpAsyncCreateSessionResponse> sessionFuture = smtpClient.createSession(
sessionData, sessionConfig, SmtpAsyncSession.DebugMode.DEBUG_OFF
);
// Check if future is done using the isDone method (non-blocking)
if (sessionFuture.isDone()) {
System.out.println("Future is ready, can access data without blocking");
} else {
System.out.println("Future is not done yet");
}
// Gets the session data from the future. This operation will block only if future is not yet complete
final SmtpAsyncCreateSessionResponse sessionResponse = sessionFuture.get();
// The actual session that can be used to issue commands
final SmtpAsyncSession session = sessionResponse.getSession();
Execute the SMTP command
The follow code snippet demonstrates how to execute an EHLO command.
// Issue an "EHLO" command asynchronously
final Future<SmtpAsyncResponse> ehloResponseFuture = session.execute(
new ExtendedHelloCommand("my_domain")
);
Handle the response from the server
Obtain the response from the future, block if necessary. The following example shows how to read the responses from the result.
try {
// Get the response, this may block for at most 5 seconds if not completed already
final SmtpAsyncResponse ehloResponse = ehloResponseFuture.get(5, TimeUnit.SECONDS);
final Collection<SmtpResponse> responsesLines = ehloResponse.getResponseLines();
// Access responses
for (final SmtpResponse response : responsesLines) {
System.out.println("Raw response: " + response.toString());
System.out.println("Reply code: " + response.getCode());
System.out.println("Message: " + response.getMessage());
}
} catch (TimeoutException e) {
System.err.println("future did not finish in time");
}
Cleanup
Close the session and client when operations are done.
session.close();
smtpClient.shutdown();
Release
This release, version 1.0.4, supports the following SMTP commands:
- EHLO
- HELO
- AUTH (PLAIN, LOGIN, XOAUTH2)
- QUIT
Version 1.0.4 adds startTls support.
-
Both ssl and startTls options are enabled
Client will first try normal ssl and detect the connection result. If successful, secure session will be created. If failed, client will close the old connection and create a new plain one. Then try startTls as fallback.
-
Only startTls option is enabled and ssl is disabled
Client won't try normal ssl. StartTls flow will be launched directly.
Basic startTls flow:
- Firstly, send EHLO command and check STARTTLS capability in response.
- Then send STARTTLS command and check if response code is 220.
- Finally, upgrade plain connection to secure connection.
This release, version 1.1.0, is the second official release. After this release, current supported SMTP commands are:
- EHLO
- HELO
- AUTH (PLAIN, LOGIN, XOAUTH2)
- DATA
- EXPN
- HELO
- HELP
- NOOP
- VRFY
- RSET
- RCPT
- QUIT
Contribute
We welcome questions, issues, and pull requests. Please refer to contributing.md for information about how to get involved.
License
This project is licensed under the terms of the Apache 2.0 open source license. Please refer to LICENSE for details.