Tuesday, April 13, 2010

Using JavaMail API with Glassfish and GMail

In this post, I'll show you how to configure JavaMail to use the SMTP server of GMail in Glassfish. This way, you avoid hardcoding server addresses in your application and make your application more portable. It also minimalizes the amount of "plumping" code.

Setup Glassfish

First, fire up the admin screen of Glassfish and click on JavaMail Sessions. Then create a new session configuration by clicking "new".

Make sure the following fields are filled in:

  • JNDI name: mail/<name>
  • Mail Host: smtp.gmail.com
  • Default User: <email>
  • Default Return Address: <email>

The JNDI name must be prefixed with "mail/". Use your GMail email address in last two fields.

Skip the Advanced settings and create additional properties at the bottom of the screen:

  • mail.smtp.socketFactory.port: 465
  • mail.smtp.port: 465
  • mail.smtp.socketFactory.fallback: false
  • mail.smtp.auth: true
  • mail.smtp.password: <gmail_password>
  • mail.smtp.socketFactory.class: javax.net.ssl.SSLSocketFactory

Use your valid GMail password in the password field. Save, and your configuration is ready for use.

Example client to send email with attachments

Next, we create a client to use the newly created JavaMail service in Glassfish. Before we can do that, we need the application server libraries: appserv-rt.jar and javaee.jar. You can find them in the lib directory of your Glassfish installation. Make sure all the libraries are in your build/class-path.

If you still get unresolved classes related to JavaMail, then you might also need the JavaMail libraries, which you can download here.

The example client below builds an email with three attachments from three different sources, and sends the email to two recipients. You have to use MIME-types to indicate the type of attachments. Save the code below as Main.java, compile, and run!

import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.activation.FileDataSource;
import javax.mail.BodyPart;
import javax.mail.Message;
import javax.mail.Multipart;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.mail.internet.MimeMessage.RecipientType;
import javax.mail.util.ByteArrayDataSource;
import javax.naming.InitialContext;

public class Main {

public void runTest() throws Exception {
InitialContext ctx = new InitialContext();
Session session =
(Session) ctx.lookup("mail/<name>");
// Or by injection.
//@Resource(name = "mail/<name>")
//private Session session;

// Create email and headers.
Message msg = new MimeMessage(session);
msg.setSubject("My Subject");
msg.setRecipient(RecipientType.TO,
new InternetAddress(
"tony@email.com",
"Tony"));
msg.setRecipient(RecipientType.CC,
new InternetAddress(
"michelle@email.com",
"Michelle"));
msg.setFrom(new InternetAddress(
"jack@email.com",
"Jack"));

// Body text.
BodyPart messageBodyPart = new MimeBodyPart();
messageBodyPart.setText("Here are the files.");

// Multipart message.
Multipart multipart = new MimeMultipart();
multipart.addBodyPart(messageBodyPart);

// Attachment file from string.
messageBodyPart = new MimeBodyPart();
messageBodyPart.setFileName("README1.txt");
messageBodyPart.setContent(new String(
"file 1 content"),
"text/plain");
multipart.addBodyPart(messageBodyPart);

// Attachment file from file.
messageBodyPart = new MimeBodyPart();
messageBodyPart.setFileName("README2.txt");
DataSource src = new FileDataSource("file.txt");
messageBodyPart.setDataHandler(new DataHandler(src));
multipart.addBodyPart(messageBodyPart);

// Attachment file from byte array.
messageBodyPart = new MimeBodyPart();
messageBodyPart.setFileName("README3.txt");
src = new ByteArrayDataSource(
"file 3 content".getBytes(),
"text/plain");
messageBodyPart.setDataHandler(new DataHandler(src));
multipart.addBodyPart(messageBodyPart);

// Add multipart message to email.
msg.setContent(multipart);

// Send email.
Transport.send(msg);
}

public static void main(String[] args) {
Main cli = new Main();
try {
cli.runTest();
} catch (Exception e) {
e.printStackTrace();
}
}
}

9 comments:

  1. Very kool article helped me a lot thanks maine

    ReplyDelete
  2. I always got Connection refused

    ReplyDelete
  3. Hi Gin-Lung Cheng

    I want code to any client can send mail for me,
    I use account Gmail, Using JSP/Servlet-JavaMail & GlassFish Server 3.0. Can you help me?

    ReplyDelete
  4. I could not get the example client to work with JDK7, Glasfish 3.1.1.

    The error message I was getting was:
    java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty

    I had to add this line to the main method...
    System.setProperty("javax.net.ssl.trustStore","C:/Dev/server/glassfish3/glassfish/domains/domain1/config/cacerts.jks");

    I assume when the code is running from within the container, then Glassfish will know the cacerts.jks location. Haven't got that far yet...

    ReplyDelete
  5. Thanks Man, you're a lifesaver, very detailed tutorial. Thanks again

    ReplyDelete
  6. javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file: java.naming.factory.initial
    at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:662)
    at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:307)
    at javax.naming.InitialContext.getURLOrDefaultInitCtx(InitialContext.java:344)
    at javax.naming.InitialContext.lookup(InitialContext.java:411)
    at MailMain.runTest(MailMain.java:33)
    at MailMain.main(MailMain.java:100)


    what can I do

    ReplyDelete
  7. javax.naming.NamingException: Lookup failed for 'mail/' in SerialContext[myEnv={java.naming.factory.initial=com.sun.enterprise.naming.impl.SerialInitContextFactory, java.naming.factory.url.pkgs=com.sun.enterprise.naming, java.naming.factory.state=com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl} [Root exception is javax.naming.NameNotFoundException: mail]

    ReplyDelete
  8. is on guaranteeing that the clients are completely ready to get to their Google Mail Accounts i.e. Gmail Accounts in a mistake free and bother free way. In such circumstances, it turns out to be verging on troublesome for Google to give Technical Support to any of it's free items and administrations. http://robertbuckner.livejournal.com/2455.html

    ReplyDelete