Class MailServerExtension
- All Implemented Interfaces:
ReportFactoryExtension
The MailServerExtension offers a standard way to access email messages, using the "imap" URL schema described in RFC5092.
Authentication is now rarely done with usernames and password alone,
so this class makes use of the KeyStore class, to store
authorization data as a SecretKey. This will work with any
JCE, JCEKS or PKCS12 format keystore, and although not a necessary part
of the API it is a convenient and secure way to store the arbitrary
authorization data required for IMAP authentication.
The example below is a complete example showing how this works. A KeyStore is specified, and will be created if it doesn't exist.
// Either javax.mail or jakarta.mail is required, the code below
// works with either
import javax.mail.*;
import javax.mail.internet.*;
// First create the extension and add it to the ReportFactory
ReportFactory factory = new ReportFactory();
MailServerExtension ext = new MailServerExtension(factory);
factory.getReportFactoryExtensions().add(ext);
String username = "user@example.com";
char[] password = "secret".toCharArray();
// Configure the extension to use a particular keystore,
// then load the authorization data from it. If it's not
// there or the keystore is missing, create the authorization
// data then save it to the keystore for next time.
ext.setKeyStore(Paths.get("keystore.jceks"), password, "jceks", null);
Json json = ext.load(username, password);
if (json == null) {
// First time login.
MailServerExtension.GMailHelper gmail = new MailServerExtension.GMailHelper();
gmail.setEmail(username);
gmail.setClientId("NNNNN.apps.googleusercontent.com");
gmail.setClientSecret("NNNNN");
gmail.setRedirectURI("http://127.0.0.1:8000/oauth");
json = ext.save(username, password, gmail.create());
}
URL2 uri = ext.createStore(json);
Store store = (Store)ext.getStore(uri);
// We are now connected to the IMAP server. To convert a message to PDF:
// Option 1 - load message via the object directly
Folder folder = store.getFolder(foldername);
if (!folder.isOpen()) {
folder.open(Folder.READ_ONLY);
}
Message message = folder.getMessage(num);
Report report = factory.createReport();
report.load(message);
// Option 2 - load message via an "imap" URL
URL2 msguri = uri.resolve("/"+folderName+"/;uid="+((UIDFolder)folder).getUID(message));
report.load(msguri);
The JSON configuration
The configuration for connecting to mail server is represented as a JSON object. The intention is this class will ship with various helpers to configure output for common mail service providers, and if one is available for your service that's what we recommend. Otherwise, a JSON object can be created manually. The fields are:
- scheme - the Mail URL scheme, should always be
"imap" - store -the store type, should always be
"imaps" - email -the email address being accessed
- server -the email server address, eg
"imap.gmail.com" - properties -an optional map of strings used configure the Java IMAP connection. A typical example would be
{"mail.imap.auth.mechanisms":"XOAUTH2","mail.imaps.sasl.enable":"true"}} - auth - a map containing the authorization details - it should contain a
typestring anddata, a map of values specific to the authorizer. For OAUTH2 authorization,auth.typeshould be"oauth2", andauth.dataa map as described in theOAuth2class.
Here is a full example of a configuration for the Google "Gmail" service,
as generated by the MailServerExtension.GMailHelper class.
{
"scheme": "imap",
"server": "imap.gmail.com",
"store": "imaps",
"email": "test@example.org",
"properties": {
"mail.imap.auth.mechanisms": "XOAUTH2",
"mail.imaps.sasl.enable": "true"
},
"auth": {
"type": "oauth2",
"data": {
"auth_uri": "https://accounts.google.com/o/oauth2/v2/auth",
"token_uri": "https://www.googleapis.com/oauth2/v4/token",
"redirect_uri": "http://127.0.0.1:8080/oauth",
"client_id": "nnnnnnnn.apps.googleusercontent.com",
"client_secret": "nnnnnnnn",
"scope": "https://mail.google.com/",
"protocol": {
"auth": {
"prompt": "consent"
}
},
}
},
}
This class requires an implementation of either the
jakarta.mail.internet or javax.mail.internet
package in the classpath; if neither is found, an exception will
be thrown from the constructor.
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic classA static helper class that allows easy creation of configuration for loading messages from Google Mail -
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionvoidconfigure(Json j) Configure the extension.createStore(Json json) Given a Json configuration, connect to the IMAP server it defines and return a URL which can be used to access that Store.Return the properties used by this class, as set bysetProperties(java.util.Properties)Return a Store matching the specified URL.JsonLoad a configuration from the KeyStore set withsetKeyStore(java.nio.file.Path, char[], java.lang.String, java.security.Provider)and saved withsave(java.lang.String, char[], Json)voidregister(ReportFactory factory) Notify this object it has beem added to a ReportFactory.voidremoveStore(URL2 uri) Remove a Store matching the specified URL.JsonSave a configuration to the KeyStore set withsetKeyStore(java.nio.file.Path, char[], java.lang.String, java.security.Provider).voidsetKeyStore(Path file, char[] storepass, String type, Provider provider) Set the KeyStore to be used with theload(java.lang.String, char[])andsave(java.lang.String, char[], Json)methodsvoidsetKeyStore(KeyStore keystore) Set the KeyStore to be used with theload(java.lang.String, char[])andsave(java.lang.String, char[], Json)methodsvoidsetProperties(Properties properties) Set the set of properties to be used with this class.voidunregister(ReportFactory factory) Notify this object it has been removed from a ReportFactory.Methods inherited from class java.lang.Object
equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, waitMethods inherited from interface org.faceless.publisher.ext.ReportFactoryExtension
load, register, unregister
-
Constructor Details
-
MailServerExtension
public MailServerExtension() -
MailServerExtension
-
-
Method Details
-
register
Description copied from interface:ReportFactoryExtensionNotify this object it has beem added to a ReportFactory. Will be called when this object is added to the list returned byReportFactory.getReportFactoryExtensions(). The default implementation is a no-op.- Specified by:
registerin interfaceReportFactoryExtension
-
unregister
Description copied from interface:ReportFactoryExtensionNotify this object it has been removed from a ReportFactory. Will be called when this object is removed from the list returned byReportFactory.getReportFactoryExtensions(). The default implementation is a no-op.- Specified by:
unregisterin interfaceReportFactoryExtension
-
configure
public void configure(Json j) Description copied from interface:ReportFactoryExtensionConfigure the extension. This method will be called by the web-service immediately after the extension is added, to pass in any parameters set by the user. The default implementation does nothing- Specified by:
configurein interfaceReportFactoryExtension
-
load
Load a configuration from the KeyStore set withsetKeyStore(java.nio.file.Path, char[], java.lang.String, java.security.Provider)and saved withsave(java.lang.String, char[], Json)- Parameters:
alias- the alias the configuration is saved aspassword- the password the configuration was saved with- Returns:
- the configuration
- Throws:
IOExceptionGeneralSecurityException
-
save
public Json save(String alias, char[] password, Json json) throws IOException, NoSuchAlgorithmException, KeyStoreException, CertificateException Save a configuration to the KeyStore set with
setKeyStore(java.nio.file.Path, char[], java.lang.String, java.security.Provider). The configuration is saved as a "secret key" with a custom type, and so requires a KeyStore that can handleSecretKeyobjects.2 Saving a configuration in this way offers an easy secure way to store login details with the same level of security as any other cryptographic material used by Java.- Parameters:
alias- the alias the configuration is saved aspassword- the password the configuration was saved withjson- the configuration to save.- Returns:
- the json parameter
- Throws:
IOExceptionNoSuchAlgorithmExceptionKeyStoreExceptionCertificateException
-
setProperties
Set the set of properties to be used with this class. Defaults toSystem.getProperties()- Parameters:
properties- the properties
-
getProperties
Return the properties used by this class, as set bysetProperties(java.util.Properties)- Returns:
- the properties
-
setKeyStore
public void setKeyStore(Path file, char[] storepass, String type, Provider provider) throws IOException, KeyStoreException, NoSuchAlgorithmException, CertificateException Set the KeyStore to be used with theload(java.lang.String, char[])andsave(java.lang.String, char[], Json)methods- Parameters:
file- the path to the KeyStorestorepass- the KeyStore store passwordtype- the KeyStore type, typically null to use the default, or eg "pkcs12", "jce" or "jceks"provider- if not null, the Provider to use to create the KeyStore object- Throws:
IOExceptionKeyStoreExceptionNoSuchAlgorithmExceptionCertificateException
-
setKeyStore
Set the KeyStore to be used with theload(java.lang.String, char[])andsave(java.lang.String, char[], Json)methods- Parameters:
keystore- the KeyStore
-
createStore
Given a Json configuration, connect to the IMAP server it defines and return a URL which can be used to access that Store.- Parameters:
json- the Json configuration- Returns:
- the base URL
- Throws:
GeneralSecurityException- if the authorization cannot be loadedIOException- if an exception occurs loading the configuration or contacting the mail server; if the latter, it will have ajavax.mail.MessagingExceptionorjakarta.mail.MessagingExceptionas its source.
-
getStore
Return a Store matching the specified URL. The URL should have been created by callingcreateStore(Json). The return value can be cast to a eitherjavax.mail.Storeorjakarta.mail.Store, depending on which version of the EE API is installed.- Parameters:
uri- the uri- Returns:
- the Store (either a
javax.mail.Storeorjakarta.mail.Store), ornullif there's no match
-
removeStore
Remove a Store matching the specified URL. The URL should have been created by callingcreateStore(Json)- Parameters:
uri- the uri
-