Search This Blog

Wednesday, 2 January 2013

Emailing - the Spring way

I am yet to work in a project that did not involve any mail related functionality. Send notification mails to admin, send alerts to users, send password mails... the use cases for mails go on.
Spring has provided a utility class that wraps around the the javax.Mail library.
So we do not need to acquire any mail Sessions, create javax.mail.Transport objects or attempt to connect with the mail server.We simply get the wrapper class and call send.
I decided to use this class to send mails using my gmail account.
The first step is to configure the MailSender class.
<bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
    <property name="host" value="smtp.gmail.com"/>
    <property name="port" value="25"/>
    <property name="username" value="#emailid"/>       
    <property name="password" value="#password"/>

    <property name="javaMailProperties">
        <props>
            <prop key="mail.transport.protocol">smtp</prop>
            <prop key="mail.smtps.auth">true</prop>
            <prop key="mail.smtp.starttls.enable">true</prop>
            <prop key="mail.smtp.ssl.enable">false</prop>
            <prop key="mail.debug">true</prop>
        </props>
    </property>
</bean>
As can be seen we have created an instance of JavaMailSenderImpl class.The class is an implementation of Spring's JavaMailSender interface. The class allows us to configure
  • creating the Mail session (all the details inside the props object),
  • the connection details(username, password, host and port) 
The next step is to use the bean in our code:
<bean id="testEmail" class="com.testmail.TestEmail">
    <property name="mailSender" ref="mailSender"/>
</bean>
The java class is as below:
public class TestEmail {
    private JavaMailSender mailSender;
    //setter getters

    public MimeMessage getMailMessage() throws MessagingException {
        final MimeMessage mimeMessage = this.mailSender.createMimeMessage();
        MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, false);
        helper.setFrom("testezest@gmail.com");
        helper.setTo("robinvarghese.j@gmail.com");
        helper.setCc("robinvarghese.j@gmail.com");
        helper.setBcc("robinvarghese.j@gmail.com");
        helper.setSubject("Mail Subject Line");
        helper.setText("This is a test mail",true);
        return mimeMessage;
    }

    public void sendMail() throws MailException, MessagingException {
        mailSender.send(getMailMessage());
    }
}
The main code is the send() method which sends the mail. The method takes the MimeMessage class as a parameter. MimeMessage  is like a POJO. We need to set our mail settings here - to, bcc, cc, subject , mail content etc.
The MimeMessageHelper class is a helper call for configuring the MimeMessage POJO. The boolean parameter in the constructor indicates that the message needs support for attachments.
Now to test the code:
public static void main(String[] args) throws MailException, MessagingException {
    ApplicationContext xmlBeanFactory = new ClassPathXmlApplicationContext(
            "spring-mail.xml");
    TestEmail mailSender = (TestEmail) xmlBeanFactory
            .getBean("testEmail");
    mailSender.sendMail();
}
On running it the logs indicate the details:
373  [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanF
actory  - Returning cached instance of singleton bean 'testEmail'
DEBUG: JavaMail version 1.4.4
DEBUG: successfully loaded resource: /META-INF/javamail.default.providers
DEBUG: Tables of loaded providers
DEBUG: Providers Listed By Class Name: {com.sun.mail.smtp.SMTPSSLTransport=javax
.mail.Provider[TRANSPORT,smtps,com.sun.mail.smtp.SMTPSSLTransport,Sun Microsyste
ms, Inc], com.sun.mail.smtp.SMTPTransport=javax.mail.Provider[TRANSPORT,smtp,com
.sun.mail.smtp.SMTPTransport,Sun Microsystems, Inc], com.sun.mail.imap.IMAPSSLSt
ore=javax.mail.Provider[STORE,imaps,com.sun.mail.imap.IMAPSSLStore,Sun Microsyst
ems, Inc], com.sun.mail.pop3.POP3SSLStore=javax.mail.Provider[STORE,pop3s,com.su
n.mail.pop3.POP3SSLStore,Sun Microsystems, Inc], com.sun.mail.imap.IMAPStore=jav
ax.mail.Provider[STORE,imap,com.sun.mail.imap.IMAPStore,Sun Microsystems, Inc], 
com.sun.mail.pop3.POP3Store=javax.mail.Provider[STORE,pop3,com.sun.mail.pop3.POP
3Store,Sun Microsystems, Inc]}
DEBUG: Providers Listed By Protocol: {imaps=javax.mail.Provider[STORE,imaps,com.
sun.mail.imap.IMAPSSLStore,Sun Microsystems, Inc], imap=javax.mail.Provider[STOR
E,imap,com.sun.mail.imap.IMAPStore,Sun Microsystems, Inc], smtps=javax.mail.Prov
ider[TRANSPORT,smtps,com.sun.mail.smtp.SMTPSSLTransport,Sun Microsystems, Inc], 
pop3=javax.mail.Provider[STORE,pop3,com.sun.mail.pop3.POP3Store,Sun Microsystems
, Inc], pop3s=javax.mail.Provider[STORE,pop3s,com.sun.mail.pop3.POP3SSLStore,Sun
 Microsystems, Inc], smtp=javax.mail.Provider[TRANSPORT,smtp,com.sun.mail.smtp.S
MTPTransport,Sun Microsystems, Inc]}
DEBUG: successfully loaded resource: /META-INF/javamail.default.address.map
DEBUG: getProvider() returning javax.mail.Provider[TRANSPORT,smtp,com.sun.mail.s
mtp.SMTPTransport,Sun Microsystems, Inc]
DEBUG SMTP: useEhlo true, useAuth false
DEBUG SMTP: trying to connect to host "smtp.gmail.com", port 25, isSSL false
220 mx.google.com ESMTP bh9sm12343985pab.12
DEBUG SMTP: connected to host "smtp.gmail.com", port: 25

EHLO <my machine ip>
250-mx.google.com at your service, [115.113.146.194]
250-SIZE 35882577
250-8BITMIME
250-STARTTLS
250-ENHANCEDSTATUSCODES
250 PIPELINING
DEBUG SMTP: Found extension "SIZE", arg "35882577"
DEBUG SMTP: Found extension "8BITMIME", arg ""
DEBUG SMTP: Found extension "STARTTLS", arg ""
DEBUG SMTP: Found extension "ENHANCEDSTATUSCODES", arg ""
DEBUG SMTP: Found extension "PIPELINING", arg ""
STARTTLS
220 2.0.0 Ready to start TLS
EHLO <my machine ip>
250-mx.google.com at your service, [115.113.146.194]
250-SIZE 35882577
250-8BITMIME
250-AUTH LOGIN PLAIN XOAUTH XOAUTH2
250-ENHANCEDSTATUSCODES
250 PIPELINING
DEBUG SMTP: Found extension "SIZE", arg "35882577"
DEBUG SMTP: Found extension "8BITMIME", arg ""
DEBUG SMTP: Found extension "AUTH", arg "LOGIN PLAIN XOAUTH XOAUTH2"
DEBUG SMTP: Found extension "ENHANCEDSTATUSCODES", arg ""
DEBUG SMTP: Found extension "PIPELINING", arg ""
DEBUG SMTP: Attempt to authenticate
DEBUG SMTP: check mechanisms: LOGIN PLAIN DIGEST-MD5 NTLM 
AUTH LOGIN
334 VXNlcm5hbWU6
dGVzdGV6ZXN0QGdtYWlsLmNvbQ==
334 UGFzc3dvcmQ6
ZXplc3RnbWFpbDEyMw==
235 2.7.0 Accepted
DEBUG SMTP: use8bit false
MAIL FROM:<testezest@gmail.com>
250 2.1.0 OK bh9sm12343985pab.12
RCPT TO:<robinvarghese.j@gmail.com>
250 2.1.5 OK bh9sm12343985pab.12
RCPT TO:<robinvarghese.j@gmail.com>
250 2.1.5 OK, duplicate recipients will be consolidated. bh9sm12343985pab.12
RCPT TO:<robinvarghese.j@gmail.com>
250 2.1.5 OK, duplicate recipients will be consolidated. bh9sm12343985pab.12
DEBUG SMTP: Verified Addresses
DEBUG SMTP:   robinvarghese.j@gmail.com
DEBUG SMTP:   robinvarghese.j@gmail.com
DEBUG SMTP:   robinvarghese.j@gmail.com
DATA
354  Go ahead bh9sm12343985pab.12
Date: Wed, 28 Nov 2012 16:11:57 +0530 (IST)
From: testezest@gmail.com
To: robinvarghese.j@gmail.com
Cc: robinvarghese.j@gmail.com
Message-ID: <1186250301.0.1354099317320.JavaMail."Robin.Varghese"@ezest-436>
Subject: Mail Subject Line
MIME-Version: 1.0
Content-Type: text/html; charset=us-ascii
Content-Transfer-Encoding: 7bit

This is a test mail
.
250 2.0.0 OK 1354099330 bh9sm12343985pab.12
QUIT
221 2.0.0 closing connection bh9sm12343985pab.12
Some interesting points:
  1. Once the mail classes in java Mail were loaded, it fetched a list of providers from its META-INF folder.
  2. Based on my settings it first connected to smtp.gmail.com using SMTP protocol. No SSL used. (I have removed my actual machine ip from the logs.)
  3. It then performed authentication for the sender details I had configured in the <props> element of my bean.
  4. It then verified all my recipient addresses. 
  5. It was only after this that the mail send instruction was sent. An OK message indicates that the mail send was successful.
The logs indicate that the mail was sent successfully. There are some additional methods that are commonly used. One is the ability add attachments to the mail:
helper.addAttachment(attachmentKey,new ByteArrayResource(data), contentType);
Sometimes we need the mails to hold certain content inline. E.g. one of the attached images needs to be visible within the mail body. For this we have the ability to set inline content.
helper.addInline(imageName, new ByteArrayResource(contents),"image/jpeg");
We had a scenario wherein we needed to send the mails using secure authentication with the MailServer. For this we have the property:
<prop key="mail.transport.protocol">smtps</prop>
In this case Secure protocol will be used at the transport layer.From Wikipedia
SMTPS refers to a method for securing SMTP with transport layer security.
It is intended to provide authentication of the communication partners, as well as 
data integrity and confidentiality.
SMTPS is not a proprietary protocol and not an extension of SMTP. It is just a way 
to secure SMTP at the transport layer.
This means that the client and server speak normal SMTP at the application layer, 
but the connection is secured by SSL or TLS. This happens when the connection is 
established before any mail data has been exchanged. Since whether or not to use 
SSL or TLS is not negotiated by the peers, SMTPS services are usually reachable on 
a dedicated port of their own.

No comments:

Post a Comment