Sending Mail with Attachment over Secure Socket Layer (SSL) through SMTP using JavaMail

The article is written for J2SE 6, JavaMail 1.4.2, JAF 1.1.1 and Eclipse IDE for Java EE Developers.

Table Of Content

  1. Introduction
  2. Mail Protocols
  3. System Requirements
  4. Setup JavaMail and JavaBeans Activation Framework
  5. Sending Messages Using the JavaMail API
  6. Resources
  7. Feedback

Introduction

The JavaMail API is an optional package (standard extension) for reading, composing, and sending electronic messages. The JavaMail API is designed to provide protocol-independent access for sending and receiving messages by dividing the API into two parts:

  • The first part speaks on how to send and receive messages independent of the provider/protocol.
  • The second part speaks the protocol-specific languages, like SMTP, POP, IMAP, and NNTP. With the JavaMail API, in order to communicate with a server, you need a provider for a protocol. The creation of protocol-specific providers is not covered in this course as Sun provides a sufficient set for free.

The procedures in this article may also apply to other SMTP servers which provide secure SSL/TLS access.

Mail Protocols

  • SMTP:
  • The Simple Mail Transfer Protocol (SMTP) is the mechanism for delivery of email.

  • POP:
  • POP stands for Post Office Protocol. Currently in version 3, also known as POP3, RFC 1939 defines this protocol. It defines support for a single mailbox for each user.

  • IMAP:
  • IMAP is a more advanced protocol for receiving messages. Defined in RFC 2060, IMAP stands for Internet Message Access Protocol, and is currently in version 4, also known as IMAP4.

Getting Started – System Requirements

Setup/Installing JavaMail and JavaBeans Activation Framework

To install, simply unzip the downloaded files, that is javamail-[version].zip and jaf-[version].zip, and add the contained jar files to your classpath. The mailapi.jar file contains the core API classes, while the pop3.jar, imap.jar and smtp.jar files contain the provider implementations for the respective mail protocols.

.;D:\javamail-1.4.2\lib\activation.jar;D:\javamail-1.4.2\lib\dsn.jar;D:\javamail-1.4.2\lib\imap.jar;D:\javamail-1.4.2\lib\mailapi.jar;D:\javamail-1.4.2\lib\pop3.jar;D:\javamail-1.4.2\lib\smtp.jar;

If you don’t want to change the CLASSPATH environment variable, copy the JAR files to your lib/ext directory under the Java Runtime Environment (JRE) directory. For instance, for the J2SE 6.0 release, the default directory would be C:\Program Files\Java\jdk1.6.0_04\jre\lib\ext on a Windows platform.

Sending Messages Using the JavaMail API

To get started we will create a simple Java Project by selecting New > Other… > Java > Java Project from the File menu. Click Next.

Name the project SendMailDemo. Click Next.

Now, select Libraries TAB. Click Add Library… and select User Library. Click Next.

Now to create Javamail Library, Click User Libraries…. User Libraries Preferences will get open. Click New…. Name Library javamail-1.4.2 and click OK. Click Add JARs… to add Jar files to javamail-1.4.2 library. Select JARs from your local system and click OK.

In User Library, check javamail-1.4.2 and click Finish. Click Finish again.

Now, create the SendMailDemoTrustManager class. Use the File > New > Class wizard, put SendMailDemoTrustManager in the Name field, edu.bhavesh.mail.smtp.ssl.factory in the Package field and Finish the wizard. Replace the contents of the generated class with the following code:

package edu.bhavesh.mail.smtp.ssl.factory;

import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import javax.net.ssl.X509TrustManager;

/**
* A Trust Manager accepting every certificate.
* 
* @author Bhavesh.Thaker
*/
public class SendMailDemoTrustManager implements X509TrustManager {

/**
* @see com.sun.net.ssl.X509TrustManager#getAcceptedIssuers()
*/
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}

/**
* @see com.sun.net.ssl.X509TrustManager#isClientTrusted(X509Certificate[])
*/
public boolean isClientTrusted(X509Certificate[] arg0) {
return true;
}

/**
* @see com.sun.net.ssl.X509TrustManager#isServerTrusted(X509Certificate[])
*/
public boolean isServerTrusted(X509Certificate[] arg0) {
return true;
}

public void checkClientTrusted(X509Certificate[] arg0, String arg1)
throws CertificateException {
// TODO Auto-generated method stub

}

public void checkServerTrusted(X509Certificate[] arg0, String arg1)
throws CertificateException {
// TODO Auto-generated method stub

}

}

Now, create the SendMailDemoSSLSocketFactory class. Use the File > New > Class wizard, put SendMailDemoSSLSocketFactory in the Name field, edu.bhavesh.mail.smtp.ssl.factory in the Package field and Finish the wizard. Replace the contents of the generated class with the following code:

package edu.bhavesh.mail.smtp.ssl.factory;

import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;

import javax.net.SocketFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;

/**
* A SSL Socket Factory for connecting and providing certificate.
* 
* @author Bhavesh.Thaker
*/
public class SendMailDemoSSLSocketFactory extends SSLSocketFactory {

// ------------------------------------------------------------ Private data
private SSLSocketFactory sslSocketFactory;

// private SocketFactory socketFactory;

// ------------------------------------------------------------ Constructors
public SendMailDemoSSLSocketFactory() {
try {
SSLContext sslcontext = SSLContext.getInstance("TLS");
sslcontext.init(null,
new TrustManager[] { new SendMailDemoTrustManager() },
new java.security.SecureRandom());
sslSocketFactory = (SSLSocketFactory) sslcontext.getSocketFactory();
} catch (Exception e) {
System.out.println("Error while creating SendMailDemoSSLSocketFactory: "
+ e.getMessage());
}
}

// ---------------------------------------------------------- Public methods

public static SocketFactory getDefault() {
return new SendMailDemoSSLSocketFactory();
}

@Override
public Socket createSocket(Socket socket, String s, int i, boolean flag)
throws IOException {
return sslSocketFactory.createSocket(socket, s, i, flag);
}

@Override
public Socket createSocket(InetAddress inaddr, int i, InetAddress inaddr1,
int j) throws IOException {
return sslSocketFactory.createSocket(inaddr, i, inaddr1, j);
}

@Override
public Socket createSocket(InetAddress inaddr, int i) throws IOException {
return sslSocketFactory.createSocket(inaddr, i);
}

@Override
public Socket createSocket(String s, int i, InetAddress inaddr, int j)
throws IOException {
return sslSocketFactory.createSocket(s, i, inaddr, j);
}

@Override
public Socket createSocket(String s, int i) throws IOException {
return sslSocketFactory.createSocket(s, i);
}

@Override
public Socket createSocket() throws IOException {
return sslSocketFactory.createSocket();
}

@Override
public String[] getDefaultCipherSuites() {
return sslSocketFactory.getSupportedCipherSuites();
}

@Override
public String[] getSupportedCipherSuites() {
return sslSocketFactory.getSupportedCipherSuites();
}
}

Now, create the SendMailDemo.properties property file. Use the File > New > File wizard, select SendMailDemo > src and put SendMailDemo.properties in the Name field, and Finish the wizard. Replace the contents of the generated class with the following code:

SMTP_HOST_NAME= mail.localhost.com
SMTP_PORT = 465
EMAIL_USERNAME = me@localhost.com
EMAIL_PASSWORD = password
EMAIL_FROM_ADDRESS = me@localhost.com
DEBUG = true

Now, create the SendMailDemo class. Use the File > New > Class wizard, put SendMailDemo in the Name field, edu.bhavesh.mail.smtp.ssl in the Package field and Finish the wizard. Replace the contents of the generated class with the following code:

package edu.bhavesh.mail.smtp.ssl;

import java.security.Security;
import java.util.Properties;
import java.util.StringTokenizer;

import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;

import com.sun.mail.smtp.SMTPSSLTransport;

/**
* @author Bhavesh.Thaker
* 
*/
public class SendMailDemo {

private static final String emailMsgTxt = "<br/><h1>
Sending mail over Secure Socket Layer (SSL) through SMTP using Java Mail</h1>
<p>
This is a test mail with <b><font color=\"#0000FF\">HTML code</font></b> and a file attachment.</p>
";
private static final String emailSubjectTxt = "A SendMailDemo test from Bhavesh Thaker";
private static final String SSL_FACTORY = "edu.bhavesh.mail.smtp.ssl.factory.SendMailDemoSSLSocketFactory";
private static final String sendTo = "me@rationaljava.blogspot.com,you@rationaljava.blogspot.com";

public static void main(String[] args) throws Exception {
// Security.setProperty("ssl.SocketFactory.provider", SSL_FACTORY);
FileDataSource fileDataSource = new FileDataSource(
"C:\\files\\filetosend.jpg") {
@Override
public String getContentType() {
return "application/octet-stream";
}
};
new SendMailDemo().sendSSLMessage(sendTo, emailSubjectTxt, emailMsgTxt,
new DataHandler(fileDataSource));
System.out.println("Sucessfully Sent mail to All Users");
}

public void sendSSLMessage(String recipients, String subject,
String message, DataHandler dataHandler) throws MessagingException {

Security.setProperty("ssl.SocketFactory.provider", SSL_FACTORY);

Properties sendMailDemoProperties = readPropertyFile("/SendMailDemo.properties");

final String smtpHostName = sendMailDemoProperties.getProperty(
"SMTP_HOST_NAME").trim();
final String smtpPort = sendMailDemoProperties.getProperty("SMTP_PORT")
.trim();
final String emailUsername = sendMailDemoProperties.getProperty(
"EMAIL_USERNAME").trim();
final String emailPassword = sendMailDemoProperties.getProperty(
"EMAIL_PASSWORD").trim();
final String emailFromAddress = sendMailDemoProperties.getProperty(
"EMAIL_FROM_ADDRESS").trim();
final String debug = sendMailDemoProperties.getProperty("DEBUG").trim();

Properties props = new Properties();
props.put("mail.smtp.auth", "true");
props.put("mail.smtp.submitter", emailUsername);
props.put("mail.smtp.user", emailUsername);
props.put("mail.smtp.host", smtpHostName);
props.put("mail.debug", debug);
props.put("mail.smtp.port", smtpPort);
props.put("mail.smtp.ssl.socketFactory.port", smtpPort);
props.put("mail.smtp.ssl.socketFactory.class", SSL_FACTORY);
props.put("mail.smtp.socketFactory.fallback", "false");
props.put("mail.smtp.ssl.enable", "true");
props.put("mail.smtp.starttls.enable", "true");

Session session = Session.getDefaultInstance(props,
new javax.mail.Authenticator() {
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(emailUsername,
emailPassword);
}
});

session.setDebug(Boolean.parseBoolean(debug));

Message msg = new MimeMessage(session);
InternetAddress addressFrom = new InternetAddress(emailFromAddress);
msg.setFrom(addressFrom);

StringTokenizer st = new StringTokenizer(recipients, ",");
String[] recipientsArray = new String[st.countTokens()];
int tokens = 0;
while (st.hasMoreTokens()) {
recipientsArray[tokens] = st.nextToken().trim();
tokens++;
}

InternetAddress[] addressTo = new InternetAddress[recipientsArray.length];
for (int i = 0; i < recipientsArray.length; i++) {
addressTo[i] = new InternetAddress(recipientsArray[i]);
}
msg.setRecipients(Message.RecipientType.TO, addressTo);

// Setting the Subject and Content Type
msg.setSubject(subject);
// Create MultiPart Object
if (dataHandler != null) {
Multipart multipart = new MimeMultipart();

MimeBodyPart messageBodyPart = new MimeBodyPart();
messageBodyPart.setContent(message, "text/html");
multipart.addBodyPart(messageBodyPart);

messageBodyPart = new MimeBodyPart();
messageBodyPart.setDataHandler(dataHandler);
messageBodyPart.setFileName(dataHandler.getDataSource().getName());
multipart.addBodyPart(messageBodyPart);
msg.setContent(multipart, "text/html");
} else {
msg.setContent(message, "text/html");
}

SMTPSSLTransport transport = (SMTPSSLTransport) session
.getTransport("smtps");
transport.connect(smtpHostName, new Integer(smtpPort).intValue(),
emailUsername, emailPassword);
msg.saveChanges();
transport.sendMessage(msg, msg.getAllRecipients());
transport.close();

}

private Properties readPropertyFile(String fileName) {
Properties objProperties = null;
try {
objProperties = new Properties();
objProperties.load(this.getClass().getResourceAsStream(fileName));
} catch (Exception e) {
System.out.println("ERROR: Could not read properties file\n");
e.printStackTrace();
}
return objProperties;
}

}

NOTE: To set your own mail server properties, change Property file and SendMailDemo.java (emailMsgTxt and sendTo variables)

Now, to execute SendMailDemo, right click on SendMailDemo and goto Run As > Java Application.

Resources

Feedback

I would like to hear from you! If you liked this tutorial, have some suggestions or even some corrections for me, please let me know. I track all user feedback in comments sections.

One Comment

  1. Chinna GVR says:

    hai buddy,
    I tried above one.
    I didn’t change anything in the above code except the properties file and SENDTO in senddemo class…
    but i’m getting the bellow exception, if you can please help me to resolve this…

    Exception in thread “main” javax.mail.NoSuchProviderException: No provider for smtps
    at javax.mail.Session.getProvider(Session.java:289)
    at javax.mail.Session.getTransport(Session.java:483)
    at javax.mail.Session.getTransport(Session.java:464)
    at sendamailnow.SendMailDemo.sendSSLMessage(SendMailDemo.java:124)
    at sendamailnow.SendMailDemo.main(SendMailDemo.java:41)

Leave a Reply

Your email address will not be published. Required fields are marked *