Technology Blogs by SAP
Learn how to extend and personalize SAP applications. Follow the SAP technology blog for insights into SAP BTP, ABAP, SAP Analytics Cloud, SAP HANA, and more.
cancel
Showing results for 
Search instead for 
Did you mean: 
Former Member


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:

SMTPS:

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.

Email received in inbox:

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





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

Case 2:      Additional security feature for Gmail

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

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

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

15 Comments