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

Any complex application or service might need one or two basic capabilities, such as sending emails. This is why we’ve published working code examples to show how to do that from an application deployable on the HANA Cloud Platform (this work was carried out together with my colleague, heiko.witteborg).

For the examples we have picked 2 service providers, Sendgrid and MailJet. They both have extensive APIs and similar capabilities. The differentiating factor is that Sendgrid is US-based, whereas MailJet is a European company – therefore abiding to the European data privacy laws.

Before moving on to the next step, it should be noted that everything we describe below is also included in the wikis of the related open-source projects found on GitHub here and here.

Here is the summary of this blog post (use the entries to navigate):

Sendgrid

In order to use the Sendgrid email service, one must first enable it via the Cloud Cockpit by accessing the Email module and performing the registration steps. This will result in getting a Sendgrid username and password.

Sending emails using Sendgrid’s Web API

The HCP platforms allows external HTTP calls through http destinations. For using Sendgrid’s Web API, one should define an http destination as follows (at account or application level):


Name=SendgridAPI
URL=https://api.sendgrid.com/api/
ProxyType=Internet
Type=HTTP
CloudConnectorVersion=2
Authentication=NoAuthentication






Simply import the destination either via the Cloud Cockpit, either via Eclipse.
To make use of it, first insert the following lines in your web.xml file:


<resource-ref>  
     <res-ref-name>connectivity/DestinationFactory</res-ref-name>  
     <res-type>com.sap.core.connectivity.api.DestinationFactory</res-type>
</resource-ref>






Then, in your code, initialize the destination:


Context ctx = new InitialContext();
DestinationFactory destinationFactory = (DestinationFactory)ctx.lookup(DestinationFactory.JNDI_NAME);
sendgridDestination = (HttpDestination) destinationFactory.getDestination("SendgridAPI");






For more information about the use of http destinations, please refer to the examples and instructions given here.

Next, we’re going to make a POST call to the endpoint URL responsible for sending emails (https://api.sendgrid.com/api/mail.send.json or https://api.sendgrid.com/api/mail.send.xml - depending on the desired response format), as specified on Sendgrid’s API reference page. This call has some mandatory parameters, but basically the POST data should look something like below:


api_user=<<your_sendgrid_username>>&<<api_key=your_sendgrid_password>>&
to[]=<<destination@example.com>>&toname[]=<<destination_name>>&
to[]=<<destination2@example.com>>&toname[]=<<destination2_name>>&
subject=Example_Subject&text=testingtextbody&
from=info@domain.com






The Java code for making such a call might look like:


public String send(String from, String to, String subject, String body) throws ClientProtocolException, URISyntaxException, DestinationException, IOException {
    String extraURL = "mail.send.json";
    return makeAPIPOSTCall(extraURL, makeParams(from, to, subject, body));
}
private List<NameValuePair> makeParams(String from, String to, String subject, String body) {
    List<NameValuePair> params = new ArrayList<NameValuePair>();
    params.add(new BasicNameValuePair("from", from));
    ArrayList<String> tos = new ArrayList<String>();
    ArrayList<String> toNames = new ArrayList<String>();
    InternetAddress[] toAddresses;
    try {
        toAddresses = InternetAddress.parse(to);
        for (int i = 0; i < toAddresses.length; i++) {
        tos.add(toAddresses[i].getAddress());
        toNames.add(toAddresses[i].getPersonal() == null ? toAddresses[i].getAddress() : toAddresses[i].getPersonal());
        }
    } catch (AddressException e) {
        e.printStackTrace();
    }
    for (int i = 0; i < tos.size(); i++) {
        params.add(new BasicNameValuePair("to[]", tos.get(i)));
        params.add(new BasicNameValuePair("toname[]", toNames.get(i)));
    }
    params.add(new BasicNameValuePair("subject", subject));
    params.add(new BasicNameValuePair("text", body));
    return params;
}
public String makeAPIPOSTCall(String extraURL, List<NameValuePair> params)
        throws ClientProtocolException, URISyntaxException, DestinationException, IOException {
    params.add(new BasicNameValuePair("api_user", "<<your_sendgrid_username>>));
    params.add(new BasicNameValuePair("api_key", "<<your_sendgrid_password>>"));
    String url = sendgridDestination.getURI() + extraURL;
    HttpClient client = sendgridDestination.createHttpClient();
    HttpConnectionParams.setConnectionTimeout(client.getParams(), 10000);
    HttpPost request = new HttpPost(url);
    request.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
    HttpResponse response = client.execute(request);
    return EntityUtils.toString(response.getEntity());
}






For a more elaborate example containing more use cases, such as handling email events, please have a look within this GitHub repository, the web-api folder.

Sending emails using Sendgrid’s Java library

Sendgrid offers a Java library for sending emails that can be found here. Their GitHub repository has a great set of examples, however, some particularities need to be handled before the library is used on HCP.

First of all, include the Java library in your application. If you have a Maven project, the easiest way is by including the following dependency in the pom.xml file:



<dependency>    
     <groupId>com.sendgrid</groupId>    
     <artifactId>sendgrid-java</artifactId>
     <version>2.2.2</version>
</dependency>







There is a small issue, in the sense that Sendgrid’s library uses a CloseableHttpClient, whereas the HCP Connectivity Service API does not accommodate that. Therefore, we need to use a workaround. The idea is to get the proxy configuration specific to our Sendgrid HTTP destination, in order to create a legitimate (in the sense that is allowed to make http calls) CloseableHttpClient to pass to the Sendgrid library. For that we need the ConnectivityConfiguration API (you may find further explanations here).

Please add the following lines to your web.xml file.



<resource-ref>    
     <res-ref-name>connectivityConfiguration</res-ref-name>    
     <res-type>com.sap.core.connectivity.api.configuration.ConnectivityConfiguration</res-type>
</resource-ref>







After that, in your code, you have to create a CloseableHttpClient like this:



public static final String SENDGRID_API_DESTINATION = "SendgridAPI";
private CloseableHttpClient makeClient() throws Exception {
    Context ctx = new InitialContext();
    connectivityConfiguration = (ConnectivityConfiguration) ctx.lookup("java:comp/env/connectivityConfiguration");
    destConfiguration = connectivityConfiguration.getConfiguration(SENDGRID_API_DESTINATION);
    String proxyType = destConfiguration.getProperty("ProxyType");
    HttpHost proxy = getProxy(proxyType);
    if (proxy == null)
        throw new Exception("Unable to get system proxy");
    CloseableHttpClient newClient = HttpClientBuilder.create().setProxy(proxy).build();
    return newClient;
}
private HttpHost getProxy(String proxyType) {
    String proxyHost = null;
    int proxyPort = 0;
    if (proxyType.equals("Internet")) {
        // Get proxy for internet destinations
        proxyHost = System.getProperty("http.proxyHost");
        proxyPort = Integer.parseInt(System.getProperty("http.proxyPort"));
        return new HttpHost(proxyHost, proxyPort);
    }
    return null;
}







Finally you may use Sendgrid’s Java library (please note that you first need to generate an API key from the Sendgrid dashboard) to use the library:


private String SENDGRID_API_KEY = "<<your_sendgrid_api_key>>";
Sendgrid sendgrid = new SendGrid(SENDGRID_API_KEY);
try {
    sendgrid.setClient(makeClient());
} catch (Exception e) {
    e.printStackTrace();
}






After this, please follow the examples given here. In the GitHub repository (the code-wrapper folder) you can find a working Maven application that you can use as a starting point.

MailJet

In order to use the Mailjet email service, one must first sign up on mailjet.com. For the newly created account Mailjet provides an API Key and a Secret Key to access the Mailjet API. These credentials can be retrieved here.

Sending emails via SMTP

The HCP platforms allows external SMTP calls through mail destinations. For using Mailjet, one should define a mail destination as follows (at application level):


Type=MAIL
Name=MAILJETSMTP
mail.description=Mailjet SMTP destination
mail.user=<<your Mailjet API Key>>
mail.password=<<your Mailjet Secret Key>>
mail.transport.protocol=smtp
mail.smtp.host=in-v3.mailjet.com
mail.smtp.port=587
mail.smtp.auth=true
mail.startttls.enable=true





You may copy and paste the previous destination description in a text file, replace the mail.user and mail.password values and import it either via the Cloud Cockpit, either via Eclipse.

Then, in your code, you will have to “read” the destination:


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





Don’t forget to import javax.mail.Session (and other javax.mail classes).

Now, for assembling an email message to be sent via SMTP, you may start from the following example code:


mimeMessage = new MimeMessage(mailSession);
try {
  InternetAddress[] fromAddress = InternetAddress.parse(this.getFrom());
    InternetAddress[] toAddresses = this.buildToAddresses();
    mimeMessage.setFrom(fromAddress[0]);
    mimeMessage.setRecipients(RecipientType.TO, toAddresses);
    mimeMessage.setSubject(this.getSubject(), "UTF-8");
    MimeMultipart multiPart = new MimeMultipart("alternative");
    MimeBodyPart part = new MimeBodyPart();
    part.setText(this.getBody(), "utf-8", "plain");
    multiPart.addBodyPart(part);
    mimeMessage.setContent(multiPart);
} catch (Exception e) {
  LOGGER.error("There was an error when initializing the mail message:");
  LOGGER.error(e.getMessage());
}





After the message has been assembled, it can be sent using the following snippet:


try {
  transport = mailSession.getTransport();
     transport.connect();
  transport.sendMessage(mimeMessage, mimeMessage.getAllRecipients());
  return "Sent"; // TODO send information equivalent to the HTTP return
} catch (Exception e) {
  LOGGER.error("Sending mail with SMTP via Mailjet API failed!", e);
  LOGGER.error(e.getMessage());
} finally {
  // Close transport layer
  if (transport != null) {
  try {
     transport.close();
  } catch (MessagingException e) {
     throw new MailException(e);
  }
  }
}



Now you may execute the code in the following manner (suppose you are doing it from a servlet), and make a POST call with parameters `from`, `to`, `subject`, `body`:


String from = request.getParameter("fromaddress");
String to = request.getParameter("toaddress");
String subjectText = request.getParameter("subjecttext");
String mailText = request.getParameter("mailtext");
AbstractMail mail = MailFactory.getMail(MailType.SMTP_MAIL);
MailjetClient mailjetClient = MailjetClient.getInstance(getServletContext(), mailSession);
try {
  mail.composeMail(from, to, subjectText, mailText);
  String sendResult = mail.send(mailjetClient);
} catch (Exception e) {
  e.printStackTrace();
}




Sending emails using Mailjet’s Web API

The HCP platforms allows external HTTP calls through http destinations. For using Mailjet’s Web API, one should define an http destination as follows (at account or application level):


Name=MAILJETAPI
URL=https://api.mailjet.com/v3/
ProxyType=Internet
Type=HTTP
CloudConnectorVersion=2
Authentication=BasicAuthentication
user=<<your Mailjet API Key>>
password=<<your Mailjet Secret Key>>



Just as in the previous case, simply replace the user and password values and import the destination either via the Cloud Cockpit, either via Eclipse.
To make use of it, first insert the following lines in your web.xml file:


<resource-ref>
  <res-ref-name>connectivity/DestinationFactory</res-ref-name>
  <res-type>com.sap.core.connectivity.api.DestinationFactory</res-type>
</resource-ref>



Then, in your code, initialize the destination:


Context ctx;
try {
  ctx = new InitialContext();
  DestinationFactory destinationFactory = (DestinationFactory)ctx.lookup(DestinationFactory.JNDI_NAME);
  mailjetDestination = (HttpDestination) destinationFactory.getDestination(MAILJET_API_DESTINATION);
} catch (NamingException | DestinationNotFoundException e) {
  e.printStackTrace();
}



For more information about the use of http destinations, please refer to the examples and instructions given here.

Next, we’re going to make a POST call to the endpoint URL responsible for sending emails as specified on Mailjet’s API reference page. This call has some mandatory parameters.

The Java code for making such a call might look like (see files HttpMail.java and MailjetClient.java😞


public String send() throws MailException {
  try {
  String extraURL = MailjetClient.actionSuffix.SEND.suffix();
  return sClient.makeAPIPOSTCall(extraURL, makeJsonParams());
  } catch (IOException | URISyntaxException | DestinationException e) {
    throw new MailException("There was an exception while sending a mail via Mailjet HTTP API: " + e.getMessage());
  }
}
private JSONObject makeJsonParams() {
  JSONObject jsonParams = new JSONObject();
  jsonParams.put("FromEmail", getFrom());
  jsonParams.put("FromName", getFrom()); // TODO
  List<Map<String, String>> recList = new ArrayList<>();
  for (int i = 0; i < getTo().size(); i++) {
  Map<String, String> curRec = new HashMap<String, String>();
  curRec.put("Email", getTo().get(i));
  curRec.put("Name", getToName().get(i));
  recList.add(curRec);
  }
  JSONArray recipients = new JSONArray(recList);
  jsonParams.put("Recipients", recipients);
  jsonParams.put("Subject", getSubject());
  jsonParams.put("Text-part", getBody());
  return jsonParams;
}
public String makeAPIPOSTCall(String extraURL, JSONObject data)
  throws ClientProtocolException, URISyntaxException, DestinationException, IOException {
  return makePOSTCall(mailjetDestination, extraURL, data.toString());
}
protected String makePOSTCall(HttpDestination destination, String extraURL, String data)
  throws URISyntaxException, DestinationException, IOException, ClientProtocolException {
  String url = destination.getURI() + extraURL;
  HttpClient client = destination.createHttpClient();
  HttpConnectionParams.setConnectionTimeout(client.getParams(), 10000);
  HttpPost request = new HttpPost(url);
  request.setHeader("Content-type", "application/json");
  request.setHeader("Accept", "application/json");
  request.setEntity(new StringEntity(data, "UTF-8"));
  HttpResponse response = client.execute(request);//httpContextsMap.get(client));
  System.err.println(response.getStatusLine().toString());
  return EntityUtils.toString(response.getEntity());
}



For a more elaborate example containing more use cases, such as handling email events, please have a look within this GitHub repository.

Sending emails using Mailjet’s Java library

Mailjet offers a Java library for sending emails that can be found here. Though not fully applicable in the context of an HCP application, it provides useful functionality that simplifies e.g. the creation of Mailjet emails compatible.

To use the Mailjet Java Wrapper on HCP, include the library in your application, e.g. by putting a copy of the library into your WebContent/WEB-INF/lib folder. If you have a Maven project: since the Mailjet Java Wrapper is not available on Maven Central, one possible way of using the library is to create an in-project repository and to put a copy there (e.g. into _repo/com/mailjet/client/3.0.0/) and include the repository and the corresponding dependency in the pom.xml file.


<repository>
     <id>repo</id>
     <name>In Project Repo</name>
     <releases>
          <enabled>true</enabled>
          <checksumPolicy>ignore</checksumPolicy>
     </releases>
     <snapshots>
          <enabled>false</enabled>
     </snapshots>
     <url>file://${project.basedir}/repo</url>
</repository>
...
<dependency>
     <groupId>com.mailjet</groupId>
     <artifactId>client</artifactId>
     <version>1.0-SNAPSHOT</version>
</dependency>



You cannot use the MailjetClient provided in the library because in HCP applications, the HTTP client and the user authorization is handled via destinations (as described above). Yet, you may use the other aspects of the library, e.g. methods to assemble the request to be send to Mailjet (see sample code😞


public String send() throws MailException {
  try {
  MailjetRequest email = new MailjetRequest(Email.resource)
                     .property(Email.FROMNAME, getFrom()) // TODO
                     .property(Email.FROMEMAIL, getFrom())
                     .property(Email.SUBJECT, getSubject())
                     .property(Email.TEXTPART, getBody())
                     .property(Email.RECIPIENTS, getRecipients(getTo()))
                     .property(Email.MJCUSTOMID, "JAVA-Email");
  String extraURL = MailjetClient.actionSuffix.SEND.suffix();
  return sClient.makeAPIPOSTCall(extraURL, email.getBody());
  } catch (AddressException | URISyntaxException | DestinationException | IOException e) {
    throw new MailException("There was an exception sending mail via Mailjet HTTP API: " + e.getMessage());
  }
}
private JSONArray getRecipients(ArrayList<String> to) throws AddressException {
  JSONArray recipients = new JSONArray();
  for (String toItem : to) {
  recipients.put(new JSONObject().put(Contact.EMAIL, toItem));
  }
  return recipients;
}



2 Comments