Skip to Content


This blog is mainly based on the detailed steps of developing a e-mail sending functionality which shows how to use the connectivity service APIs to send e-mail. For any application that is applicable for a particular business operations, sending email to a group of users is a common feature that needs to be incorporated in the UI either as a button feature or hyperlink.

The example  is a stand alone application that provides a simple User Interface to compose an e-mail message and send it.The e-mail connectivity functionality allows us to send electronic mail messages from our Web applications using e-mail providers that are accessible on the Internet, such as Google Mail (Gmail).

To send and fetch e-mail, the following configurations are required:

  • Obtain a mail session resource using resource injection or, alternatively, using a JNDI lookup.
  • Configure the mail session resource by specifying the protocol settings of the mail server as a mail destination configuration. SMTP/SMTPS is supported for sending e-mail, and POP3 and IMAP for retrieving messages from a mailbox account.
  • In the Web application, use the JavaMail API (javax.mail) to create and send a MimeMessage object or retrieve e-mails from a message store.

Most of the steps are just the same as mentioned in SAP HANA Cloud Platform documentation. Apart from that, I have tried to cover few troubleshooting steps which I have experienced while developing it. All these information are available in bits and pieces and I have tried to consolidate them in a single blog. So following this steps will actually help us to create a stand alone email sending application which can be consumed by the mail sending feature in any Business Applications in HCP.


JavaMail API

The JavaMail API provides classes that model a mail system. The javax.mail package defines classes that are common to all mail systems. The javax.mail.internet package defines classes that are specific to mail systems based on internet standards such as MIME, SMTP, POP3, and IMAP. The JavaMail API includes the javax.mail package and sub-packages.

Mail Session


A servlet can obtain a mail session resource using resource injection or a JNDI lookup. The properties of the mail session are specified by a mail destination configuration. So that the resource is linked to this configuration, the names of the destination configuration and mail session resource must be the same.

  • Resource injection: We can directly inject the mail session resource using annotations as shown in the example below. We do not need to declare the JNDI resource reference in the web.xml deployment descriptor.
    @Resource(name = "mail/Session") private javax.mail.Session mailSession; 
  • JNDI lookup: To obtain a resource of type javax.mail.Session, we declare a JNDI resource reference in the web.xml deployment descriptor in the WebContent/WEB-INFdirectory as shown below. Note that the recommended resource reference name is Session and the recommended subcontext is mail (mail/Session):
    <resource-ref> <res-ref-name>mail/Session</res-ref-name> <res-type>javax.mail.Session</res-type> </resource-ref> 

    An initial JNDI context can be obtained by creating a javax.naming.InitialContext object. We can then consume the resource by looking up the naming environment through the InitialContext, as follows:

    InitialContext ctx = new InitialContext(); Session mailSession = (Session)ctx.lookup("java:comp/env/mail/Session");

Sending E-Mail

With the javax.mail.Session object we have retrieved, we can use the JavaMail API to create a MimeMessage object with its constituent parts (instances ofMimeMultipart and MimeBodyPart). The message can then be sent using the send method from the Transport class:

Transport transport = mailSession.getTransport();

transport.connect();

MimeMessage mimeMessage = new MimeMessage(mailSession);

transport.sendMessage(mimeMessage, mimeMessage.getAllRecipients());

transport.close();

Source Code:

The functionality of this servlet is to get user input in its HTTP Servlet request and based on the values of the destination email address, the mail will be triggered from the application. However the sender address is the address that is maintained in the connectivity destination


package com.sap.cloud.sample.mail;
import java.io.IOException;
import java.io.PrintWriter;
import javax.annotation.Resource;
import javax.mail.Message.RecipientType;
import javax.mail.MessagingException;
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.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Servlet implementing a mail example which shows how to use the connectivity service APIs to send e-mail.
* The example provides a simple UI to compose an e-mail message and send it. The post method uses
* the connectivity service and the javax.mail API to send the e-mail.
*/
public class MailServlet extends HttpServlet {
  @Resource(name = "mail/Session")
  private Session mailSession;
  private static final long serialVersionUID = 1L;
  private static final Logger LOGGER = LoggerFactory.getLogger(MailServlet.class);
  /** {@inheritDoc} */
  @Override
  protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  // Show input form to user
  response.setHeader("Content-Type", "text/html");
  PrintWriter writer = response.getWriter();
  writer.write("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" "
  + "\"http://www.w3.org/TR/html4/loose.dtd\">");
  writer.write("<html><head><title>Mail Test</title></head><body>");
  writer.write("<form action='' method='post'>");
  writer.write("<table style='width: 100%'>");
  writer.write("<tr>");
  writer.write("<td width='100px'><label>From:</label></td>");
  writer.write("<td><input type='text' size='50' value='' name='fromaddress'></td>");
  writer.write("</tr>");
  writer.write("<tr>");
  writer.write("<td><label>To:</label></td>");
  writer.write("<td><input type='text' size='50' value='' name='toaddress'></td>");
  writer.write("</tr>");
  writer.write("<tr>");
  writer.write("<td><label>Subject:</label></td>");
  writer.write("<td><textarea rows='1' cols='100' name='subjecttext'>Subject</textarea></td>");
  writer.write("</tr>");
  writer.write("<tr>");
  writer.write("<td><label>Mail:</label></td>");
  writer.write("<td><textarea rows='7' cols='100' name='mailtext'>Mail Text</textarea></td>");
  writer.write("</tr>");
  writer.write("<tr>");
  writer.write("<tr>");
  writer.write("<td><input type='submit' value='Send Mail'></td>");
  writer.write("</tr>");
  writer.write("</table>");
  writer.write("</form>");
  writer.write("</body></html>");
  }
  /** {@inheritDoc} */
  @Override
  protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException,
  IOException {
  Transport transport = null;
  try {
  // Parse form parameters
  String from = request.getParameter("fromaddress");
  String to = request.getParameter("toaddress");
  String subjectText = request.getParameter("subjecttext");
  String mailText = request.getParameter("mailtext");
  if (from.isEmpty() || to.isEmpty()) {
  throw new RuntimeException("Form parameters From and To may not be empty!");
  }
  // Construct message from parameters
  MimeMessage mimeMessage = new MimeMessage(mailSession);
  InternetAddress[] fromAddress = InternetAddress.parse(from);
  InternetAddress[] toAddresses = InternetAddress.parse(to);
  mimeMessage.setFrom(fromAddress[0]);
  mimeMessage.setRecipients(RecipientType.TO, toAddresses);
  mimeMessage.setSubject(subjectText, "UTF-8");
  MimeMultipart multiPart = new MimeMultipart("alternative");
  MimeBodyPart part = new MimeBodyPart();
  part.setText(mailText, "utf-8", "plain");
  multiPart.addBodyPart(part);
  mimeMessage.setContent(multiPart);
  // Send mail
  transport = mailSession.getTransport();
  transport.connect();
  transport.sendMessage(mimeMessage, mimeMessage.getAllRecipients());
  // Confirm mail sending
  response.getWriter().println(
  "E-mail was sent (in local scenario stored in '<local-server>/work/mailservice'"
  + " - in cloud scenario using configured mail session).");
  } catch (Exception e) {
  LOGGER.error("Mail operation failed", e);
  throw new ServletException(e);
  }
finally {
  // Close transport layer
  if (transport != null) {
  try {
  transport.close();
  } catch (MessagingException e) {
  throw new ServletException(e);
  }
  }
  }
  }
}

Mail Destinations


A mail destination is used to specify the mail server settings for sending or fetching e-mail, such as the e-mail provider, e-mail account, and protocol configuration. The name of the mail destination must match the name used for the mail session resource. We can configure a mail destination directly in a destination editor or in a mail destination properties file. The mail destination then needs to be made available in the cloud. If a mail destination is updated, an application restart is required so that the new configuration becomes effective. The SMTP and SMTPS configurations in the destinations are shown below. This is shown for gmail domain server. In case of any other domain, we need to provide the SMTP host and port number for that particular domain.

SMTP:

/wp-content/uploads/2015/05/smtp_destination_712322.jpg

SMTPS:

/wp-content/uploads/2015/05/smtps_712871.jpg

Testing the application:

Once the application is deployed to HCP, it can be accessed using the application URL which opens a simple HTML form for the user to fill up the relevant details.

Example: hcpdemotest@gmail.com is configured as the sender email id in this application.The credentials have been provided in the destination itself. However, the receiver email id is based upon user’s choice. Here sourav.mukherjee@sap.com is used as recipient id.

/wp-content/uploads/2015/05/form_712872.jpg

Email received in inbox:

ScreenHunter_174 May. 26 16.08.jpg

Common Troubleshooting Techniques:


In case of SMTP configuration for Gmail, the servlet may throw Authentication failed exception because of the following reasons:


  • If the server zones for HCP and Gmail are different, then google mail server will block the access. In that case, the gmail settings need to be configured for allowing access to less secure applications.


  • If the authentication issue still persists, users can use display unlock captcha feature for getting the limited access for that application. However for SMTPS configuration, such issues may not appear.



Error Message: javax.mail.AuthenticationFailedException issue



Case 1:      For Security Problem:


URL:          https://www.google.com/settings/security/lesssecureapps





/wp-content/uploads/2015/05/security_mail_712197.jpg

Enable access to less secure application from other devices or servers:

Security.jpg

Case 2:      Additional security feature for Gmail

URL:           https://accounts.google.com/DisplayUnlockCaptcha

ScreenHunter_178 May. 26 17.36.jpg

By continuing to this, user can unlock the Captcha mechanism.

ScreenHunter_179 May. 26 17.37.jpg

Note:

We can also achieve the same functionality using XSJS in XS based applications as written in How to send mail from a productive HANA XS application

To report this post you need to login first.

14 Comments

You must be Logged on to comment or reply to a post.

  1. Gregory Tutt

    Hey mate,

    Thanks for your blog… I tried following your approach but I am having an error message. I think my destination is configured correctly, the only difference is that I am running the app on a Tomcat 7.

    My error message is: Provider class does not have a constructor(Session, URLName): protocol=smtp; type=javax.mail.Provider$Type@5b915727; class=”com”.sun.mail.smtp.SMTPTransport; vendor=Oracle

    [EDIT] We found a solution… We found out that one of our library had a conflict Session, two classes were loaded… We just removed one of the libraries (and fixed all issues raised by removing this library) and it worked.

    Cheers

    Greg

    (0) 
  2. Chandan Jash

    Hi Sourav,

    Thank you so much for your posting. I have tried the same in my HCP trial account but I am not able to successfully load the mail sending page. The mail sending UI is appearing properly in local eclipse web server. I have created the web.xml file also with the details like below

    <?xml version=”1.0″ encoding=”UTF-8″?>

    <web-app id=”WebApp_ID” version=”3.0″ xmlns=”http://java.sun.com/xml/ns/javaee” xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance” xsi:schemaLocation=”http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd“>

    <display-name>chanjashmail</display-name>

    <servlet>

    <servlet-name>chanjashmail</servlet-name>

    <servlet-class>com.mytest.sample.MyMailServlet</servlet-class>

    </servlet>

      <servlet-mapping>

        <servlet-name>chanjashmail</servlet-name>

        <url-pattern>*.html</url-pattern>

      </servlet-mapping>

    </web-app>

    chanjashmail – is my webdynamic project name and I have put your code within com.mytest.sample.MyMailServlet package under src.

    I am getting  HTTPs – 404 error when I am running the application in SAP HCP.

    Can you please tell me if I am missing any part.

    Thanks in advance,

    Chandan

    (0) 
    1. Sourav Mukherjee Post author

      Hi Chandan,

      Please keep your servlet name same as your class name, not your dynamic project name. You can use a format like this.

      <servlet>

              <servlet-name>MailServlet</servlet-name>

              <servlet-class>com.sap.cloud.sample.mail.MailServlet</servlet-class>

          </servlet>

          <servlet-mapping>

              <servlet-name>MailServlet</servlet-name>

              <url-pattern>/</url-pattern>

          </servlet-mapping>

      (0) 
  3. Srikanta Satapathy

    Hi Sourav,

    Nice article. I have followed the same step you have provided. But it is throwing me NullPointer Exception on the line. ” transport = mysession.getTransport();” I debug the application and find the mySession value as null. On the top of the code I have used the following code.

    @Resource(name = “mail/Session”)

        private Session mysession;

    I have created the mail destination name as “Session”

    All other things in the application is as per the above instruction. can you please suggest, if I am missing something.

    Thanks,

    Srikanta Satapathy

    (0) 
  4. Srikanta Satapathy

    Hi Sourav,

    Now I tried to use the JNDI lookup . I added the following code in web.xml file

    <resource-ref>

           <res-ref-name>mail/Session</res-ref-name>

           <res-type>javax.mail.Session</res-type>

       </resource-ref> 

    and in Servlet I just added the below code.

    InitialContext ctx = new InitialContext();

            mysession = (Session) ctx.lookup(“java:comp/env/mail/Session”);

    I debug the application and I found the following exception.

    javax.naming.NamingException: Error while attempting to resolve reference [Root exception is javax.naming.NamingException: Cannot create resource  object instance due to exception in the object factory [Root exception is com.sap.jpaas.service.mail.service.MailServiceException: The mail destination ‘Session’ is configured on level ‘Account’, which is not supported.

    Mail destinations may only be configured on application level.]]

    I am using hana trial account. Is it something not possible using hana trial account. Am I doing something wrong? Please reply back.

    Thanks,

    Srikanta Satapathy

    (0) 
    1. Sourav Mukherjee Post author

      Hi Srikanta,

      It looks like you have created the destination in your account level directly. So your java application cannot refer it from the class.

      Follow the steps:

      Login to your cockpit -> Go to java applications -> Select the application from the list -> On opening the application details page, Go to destinations tab -> Here you have to create your destination named “Session”. this will bind your destination with your application.

      Cheers,

      Sourav

      (0) 
    1. He Yang

      Hi Ulrich,

      Thank you very much for your information.

      Does HCP Java Instance includes a default mail server or mail service?

      And since the corporate email service is not reachable from Cloud, what could be the alternative implementations?


      Due to business requirements, the email notifications has to be sent from the SAPUI5 app. So the “<form action=”MAILTO:someone@sap.com” method=”post” enctype=”text/plain”>” method will not be considered unless there is no other way.

      Please advise.

      Thanks.

      Yang He

      (0) 
  5. Gaurav Singh

    Hi Sourav

    Where do we give these e-mail destinations in tomcat server?

    It shows following message

    “E-mail was sent (in local scenario stored in ‘<local-server>/work/mailservice’ – in cloud scenario using configured mail session).”

    but I never get an e-mail

    What could be missing here?

    (0) 
    1. Sourav Mukherjee Post author

      Hi Gaurav,

      For local server, you have to create the destination from Eclipse only.

      Also for local testing, you will never get email in your mail box. Instead you will get the .msg file  in your workspace in local system . You can search for the folder work/mailservice. in your local drive. You will get those files there.

      Cheers,

      Sourav

      (1) 
        1. Sourav Mukherjee Post author

          You need to use J2EE perspective but you can create destination by opening the local server that you configured in your eclipse. You will find a connectivity tab in your local server. There you can create a new destination.

          (0) 
  6. Avanthi K

    Hi Sourav,

    I have followed the same step you have provided.  But it is throwing me following exception

      HTTP Status 500 – javax.mail.MessagingException: Could not connect to SMTP host: smtp.gmail.com, port: 587;

    Am I missing out something?

    Thanks,

    Avanthi

    (0) 

Leave a Reply