Friday, February 26, 2010

Sending email via Glassfish v3

The programmer's task


From the programmer's standpoint Java EE 5 makes sending emails very easy. In the component's class responsible for sending emails (eg. a servlet or an EJB bean) he/she declares a field of javax.mail.Session class and annotates it with javax.annotations.Resource annotation. The name attribute of this annotation holds the name of the Java Mail resource defined and configured on the application server. During the component's initialization the container performs the dependency injection which includes an inspection of all fields annotated with this annotation. Once it stumbles upon such a field it reads the name attribute and tries to find a corresponding resource. If it succeeds it injects the resource to the field. If the lookup fails the container raises an exception and prevents the component from being used.


@Resource(name = "mail/myMailSession")
private Session mailSession;


The code that constructs, initializes and sends an email message can look as follows:


// Create the message object
Message message = new MimeMessage(mailSession);

// Adjust the recipients. Here we have only one
// recipient. The recipient's address must be
// an object of the InternetAddress class.
message.setRecipients(Message.RecipientType.TO,
InternetAddress.parse(to, false));

// Set the message's subject
message.setSubject(subject);

// Insert the message's body
message.setText(msg);

// This is not mandatory, however, it is a good
// practice to indicate the software which
// constructed the message.
message.setHeader("X-Mailer", "My Mailer");

// Adjust the date of sending the message
Date timeStamp = new Date();
message.setSentDate(timeStamp);

// Use the 'send' static method of the Transport
// class to send the message
Transport.send(message);



The administrator's task


Once the code is compiled and packaged to the war or ear archive it is the time to deploy it on the application server. Before the application is deployed it is necessary to configure all resources required by the application. The Java Mail session is one of these resources. In the following paragraph I'm going to explain the procedure of setting up a Java Mail session which is able to send messages via SSL (Secure Sockets Layer) protocol.

The SSL protocol provides a secure way for exchanging data on the internet including eg. web browsing or electronic mail. In this example I will show how to configure a Java Mail session resource on the Sun Glassfish v3 application server. Its purpose is to forward the emails to an SMTP server over the SSL protocol. I assume that the SMTP server requires authentication.

Note: This type of connection is available for users of Google Mail (Gmail).

First of all open the Glassfish administration console (eg. http://localhost:4848). Then go to the Resources/JavaMail Sessions section and click on the New button situated above the table in the right panel.

Now enter the name of the JavaMail session that must match the value of the name attribute in the Resource annotation. In my example the value is mail/myMailSession.

The other parameters should be configured as follows:

  • Mail Host - the SMTP host, eg. smtp.gmail.com.

  • Default User - your user name at Gmail, eg. zslajchrt@gmail.com.

  • Default Return Address - the email address used by the application server when the message does not contain the sender's address. In the case of Gmail it matches the default user, eg. zslajchrt@gmail.com.

  • Description - the descripton of the session is not mandatory.

  • Status - Enabled.

  • Store Protocol and Store Protocol Class - leave the values as they are.

  • Transport protocol - change it to smtps.

  • Transport class - change it to com.sun.mail.smtp.SMTPSSLTransport.


So far you have configured the standard JavaMail session properties. However, the connection you are configuring requires several additional properties to be specified. These properties are added to the table located right bellow the standard properties. A property is added by clicking on Add Property button in the Additional Properties table.

Add in turn the following properties with their values:

  • mail-smtps-auth - it specifies that the connection requires authentication of the client. As the value put here true.

  • mail-smtps-password - your password for the account at Gmail.


Now the mail session should be complete and you would be able to deploy and run your application.

11 comments:

  1. hey m relatively new to jsp especially servlets....m really confused about what the servlet would look like...could u plzz help me out. Thanks a lot.

    ReplyDelete
  2. Thanks a lot for posting this. I've been trying to figure this out since a week! Works beautifully :)

    ReplyDelete
  3. Very nice write-up, Zbyněk!

    However, when I follow the steps exactly I get (with GF 3.1 B17):

    javax.mail.MessagingException: Could not connect to SMTP host: smtp.gmail.com, port: 465
    at com.sun.mail.smtp.SMTPTransport.openServer(SMTPTransport.java:1706) ~[mail.jar:1.4.3]
    at com.sun.mail.smtp.SMTPTransport.protocolConnect(SMTPTransport.java:525) ~[mail.jar:1.4.3]
    at javax.mail.Service.connect(Service.java:313) ~[mail.jar:1.4.3]
    at javax.mail.Service.connect(Service.java:172) ~[mail.jar:1.4.3]
    at javax.mail.Service.connect(Service.java:121) ~[mail.jar:1.4.3]
    at javax.mail.Transport.send0(Transport.java:190) ~[mail.jar:1.4.3]
    at javax.mail.Transport.send(Transport.java:120) ~[mail.jar:1.4.3]
    Caused by: java.net.SocketException: java.security.NoSuchAlgorithmException: Error constructing implementation (algorithm: Default, provider: SunJSSE, class: com.sun.net.ssl.internal.ssl.DefaultSSLContextImpl)
    at javax.net.ssl.DefaultSSLSocketFactory.throwException(SSLSocketFactory.java:179) ~[na:1.6]
    at javax.net.ssl.DefaultSSLSocketFactory.createSocket(SSLSocketFactory.java:186) ~[na:1.6]
    at com.sun.mail.util.SocketFetcher.createSocket(SocketFetcher.java:276) ~[mail.jar:1.4.3]
    at com.sun.mail.util.SocketFetcher.getSocket(SocketFetcher.java:227) ~[mail.jar:1.4.3]
    at com.sun.mail.smtp.SMTPTransport.openServer(SMTPTransport.java:1672) ~[mail.jar:1.4.3]
    ... 85 common frames omitted
    Caused by: java.security.NoSuchAlgorithmException: Error constructing implementation (algorithm: Default, provider: SunJSSE, class: com.sun.net.ssl.internal.ssl.DefaultSSLContextImpl)
    at java.security.Provider$Service.newInstance(Provider.java:1245) ~[na:1.6.0_20]
    at sun.security.jca.GetInstance.getInstance(GetInstance.java:220) ~[na:1.6.0_20]
    at sun.security.jca.GetInstance.getInstance(GetInstance.java:147) ~[na:1.6.0_20]
    at javax.net.ssl.SSLContext.getInstance(SSLContext.java:125) ~[na:1.6]
    at javax.net.ssl.SSLContext.getDefault(SSLContext.java:68) ~[na:1.6]
    at javax.net.ssl.SSLSocketFactory.getDefault(SSLSocketFactory.java:102) ~[na:1.6]
    at com.sun.mail.util.SocketFetcher.createSocket(SocketFetcher.java:275) ~[mail.jar:1.4.3]
    ... 87 common frames omitted
    Caused by: java.security.UnrecoverableKeyException: Password must not be null
    at sun.security.provider.JavaKeyStore.engineGetKey(JavaKeyStore.java:107) ~[na:1.6.0_20]
    at sun.security.provider.JavaKeyStore$JKS.engineGetKey(JavaKeyStore.java:38) ~[na:1.6.0_20]
    at java.security.KeyStore.getKey(KeyStore.java:763) ~[na:1.6.0_20]
    at com.sun.net.ssl.internal.ssl.SunX509KeyManagerImpl.(SunX509KeyManagerImpl.java:113) ~[na:1.6]
    at com.sun.net.ssl.internal.ssl.KeyManagerFactoryImpl$SunX509.engineInit(KeyManagerFactoryImpl.java:48) ~[na:1.6]
    at javax.net.ssl.KeyManagerFactory.init(KeyManagerFactory.java:239) ~[na:1.6]
    at com.sun.net.ssl.internal.ssl.DefaultSSLContextImpl.getDefaultKeyManager(DefaultSSLContextImpl.java:170) ~[na:1.6]
    at com.sun.net.ssl.internal.ssl.DefaultSSLContextImpl.(DefaultSSLContextImpl.java:40) ~[na:1.6]
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[na:1.6.0_20]
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39) ~[na:1.6.0_20]
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27) ~[na:1.6.0_20]
    at java.lang.reflect.Constructor.newInstance(Constructor.java:513) ~[na:1.6.0_20]
    at java.lang.Class.newInstance0(Class.java:355) ~[na:1.6.0_20]
    at java.lang.Class.newInstance(Class.java:308) ~[na:1.6.0_20]
    at java.security.Provider$Service.newInstance(Provider.java:1221) ~[na:1.6.0_20]

    Any ideas?

    ReplyDelete
  4. Thank you very much. It helps me a lot

    ReplyDelete
  5. Dont you have to specifiy the port for smtp.gmail.com?

    ReplyDelete
  6. Very nicely done. It worked perfectly.

    ReplyDelete
  7. Thank you for posting this

    tounsi-cool.net

    ReplyDelete
  8. Does someone know how can i achieve this with Outlook ?

    ReplyDelete

About Me

My Photo
Cokoliv říkáme, je až na výjimky jinak.

Followers