Finally, after a whole week, I have managed to solve a problem that had been bugging me so much that my mind didn’t quite rest even in sleep. So how do you use a SMTP host that requires authentication and gives a self-signed certificate that the client (Tomcat web server) has to acknowledge? After much googling, I found two examples, each solving a different part of my problem, but no example solving both.
Before locating the two examples, I had turned to the JavaMail API – FAQ to learn how to connect to the SMTP server given a user name and password. The method given resulted in my program generating an exception with the message “unable to find valid certification path to requested target”. It was caused by the Transport class not accepting the self-signed certificate by the host.
Then the first example is a program that allows a user to install a self-signed certificate into the trust store on the client system. The FAQ contains a link to Andreas Sterbenz’s Blog that explains and lists the code. However, this code still didn’t work with the authentication method in the FAQ. The exception persisted as the Transport class didn’t use the keystore with the new certificate.
The second example is an alternative way of performing authentication with the SMTP host. It makes use of an Authenticator class to store the user name and password which can be called by the Transport class. However, it was the same result as with the previous example.
I noticed that for both cases, the Transport class couldn’t make use of the program that store the certificate to trust the certificate. I knew I have to find a way to make the Transport class connect with the socket obtained using the first example. However, the FAQ method definitely cannot be used with the first example as the SMTPTransport class though allowing connecting with a socket, it then no longer allows connecting with a user name and password again. I made the mistake of going through all the effort of writing test code to prove myself correct.
It was by this time that I realised I could make use of the second example to just do a connect once. That was, use a SMTPTransport class which has been preset with an authenticator to connect to a socket loaded with the trust manager. Prior to this, I also made some changes to the SavingTrustManager to incorporate an old code from Novell’s contribution to OpenLDAP.
My sample codes are linked below:
- SavingTrustManager.java (class to check and save certificate)
- EmailAuthenticator.java (class to store username and password)
- EmailBean.java (class that do the sending)
The JSP that calls EmailBean to send an email is as follows:
char SEP = java.io.File.separatorChar;
String dir = System.getProperty(“java.home”) + SEP + “lib” + SEP + “security” + SEP + “cacerts”;
String email_addr = request.getParameter(“email_addr”);
String subject_header = request.getParameter(“subject_header”);
String message_body = request.getParameter(“message_body”);
EmailBean emailer = new EmailBean();
Message msg = emailer.getMimeMessage();
msg.setFrom(new InternetAddress(“ot.admin”, “OTIS Admin”));
msg.addRecipient(Message.RecipientType.TO, new InternetAddress(email_addr, “Email Form”));