Technical Articles
Mail Package deprecated – ASMA and parameterized Java map to the rescue
Motivation and introduction
I had a requirement to send messages to different mail receivers. Depending on a value
in the XML payload being sent, two different email receivers should receive the messages.
I was used to set different email receivers in the message mapping (XSLT mapping).
Depending on flags/different values in payloads, I would set different receiver addresses.
Now I had a look at Eng Swee Yeoh blog about the deprecated mail package
https://blogs.sap.com/2016/03/10/stop-using-mail-package-simplify-your-mail-receiver-adapter-scenarios/
explaining that mail package is not an option anymore.
Also in Eng Swee’s blog he hard codes the receiver email addresses in the java mapping. That is a valid option but knowing in our environment these could possibly change over time and every time I would have to touch the java mapping which I do not want to do.
In my scenario there is a mapping involved that creates an HTML table in the body of the email. I did not test this with a “pass through” scenario but it should work very similarly.
(Possible) Solution
So I came up with a combination of a parameterized java map and ASMA (Adapter Specific Message Attributes) making use of the operation mapping parameters in the iFlow/Integrated configuration to hold the actual email addresses. Any time there is a change to the receiving email addresses I can modify these easily without having to change the java map.
- Operation mapping
In my operation mapping I set parameters for the 2 different mail receivers and the XML element name I use from the payload to set the receivers:
- iFlow – mapping parameters
In my iFlow I am setting “SalesOrg” as the XML element I will read from the payload and I fill the different email receiver addresses:
- Java map
In the Java map I use DOM to parse the payload, I write into the message log (https://blogs.sap.com/2013/09/30/writing-log-entries-to-audit-log-of-the-message-from-custom-java-mapping-program/) and read parameters from the operation mapping:
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Map;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import com.sap.aii.mapping.api.AbstractTransformation;
import com.sap.aii.mapping.api.DynamicConfiguration;
import com.sap.aii.mapping.api.DynamicConfigurationKey;
import com.sap.aii.mapping.api.StreamTransformationConstants;
import com.sap.aii.mapping.api.StreamTransformationException;
import com.sap.aii.mapping.api.TransformationInput;
import com.sap.aii.mapping.api.TransformationOutput;
public class SetMailReceivers extends AbstractTransformation {
String tagValue;
//let's create the dynamic configuration key for the recipients
//we only want to set the email receivers:
private static final DynamicConfigurationKey KEY_RECIPIENTS = DynamicConfigurationKey
.create("http://sap.com/xi/XI/System/Mail", "THeaderTO");
@Override
public void transform(TransformationInput transformationInput, TransformationOutput transformationOutput) throws StreamTransformationException {
Map mapParameters = (Map) transformationInput.getInputHeader().getAll();
//get the dynamic configuration
DynamicConfiguration conf = (DynamicConfiguration) mapParameters
.get(StreamTransformationConstants.DYNAMIC_CONFIGURATION);
try {
InputStream inputstream = transformationInput.getInputPayload().getInputStream();
OutputStream outputstream = transformationOutput.getOutputPayload().getOutputStream();
//get the message ID, we need it to add a message to the monitoring message
String messageID = transformationInput.getInputHeader().getMessageId();
//create an input stream to read the payload using DOM
InputStream inputstreamDOM = transformationInput.getInputPayload().getInputStream();
//start reading XML with DOM
Document document = createDocument(inputstreamDOM);
//in the operation mapping we set the tag name that we want to read from
//the payload to determine our email receivers:
String elementToReadFromPayload = transformationInput.getInputParameters().getString("elementToReadFromPayload");
AddAuditLogs.execute("elementToReadFromPayload contains: " + elementToReadFromPayload, messageID, "success");
//get specific nodes with tag name contained in "elementToReadFromPayload"
NodeList nl = document.getElementsByTagName(elementToReadFromPayload);
//instead of "i < nl.getLength()" we just do "i < 1" - we only look at the first occurrence
//of our element with tag name "elementToReadFromPayload"
for(int i=0;i<1;i++){
Node messageNode = nl.item(i);
String nodename = messageNode.getNodeName();
if(nodename.equals(elementToReadFromPayload)){
tagValue = messageNode.getFirstChild().getNodeValue();
//add to message monitoring log what tag we read and what it contains
AddAuditLogs.execute("found Element " + nodename + " contains: " + tagValue, messageID, "success");
}
}
//now get the other parameters we set in the Operation mapping which will contain the
//two sets of email receivers:
String receivers1 = transformationInput.getInputParameters().getString("mail1");
String receivers2 = transformationInput.getInputParameters().getString("mail2");
//add to monitoring log what parameters we read and what they contain:
AddAuditLogs.execute("mail1 contains: " + receivers1, messageID, "success");
AddAuditLogs.execute("mail2 contains: " + receivers2, messageID, "success");
//now put the recipients into the dynamic configuration and we are done :-)
//depending on the value in the XML element we read (elementToReadFromPayload)
//we now set the receivers:
if (tagValue.contains("1710")) {
conf.put(KEY_RECIPIENTS, receivers2);
}else {
conf.put(KEY_RECIPIENTS, receivers1);
}
// b) Just copy Input file content to Output file content
byte[] b = new byte[inputstream.available()];
inputstream.read(b);
outputstream.write(b);
} catch(Exception exception) {
getTrace().addDebugMessage(exception.getMessage());
throw new StreamTransformationException(exception.toString());
}
}
//create the DOM Document
public static Document createDocument(InputStream inputstreamDOM) throws ParserConfigurationException, IOException, SAXException {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder db = factory.newDocumentBuilder();
Document document = db.parse(inputstreamDOM);
document.getDocumentElement().normalize();
return document;
}
}
- Mail receiver channel
I set ASMA in the Mail receiver channel. All possible ASMA attributes for mail receiver adapters can be found here: https://help.sap.com/viewer/5cf7d2de571a45cc81f91261668b7361/7.3.20/en-US/6b4493404f673028e10000000a1550b0.html
Under tab “General” I just set an underscore in the “To” field and hardcoded the CC: values:
Testing the scenario
Once starting the scenario and triggering a message to the mail receiver channel, we are able to see audit entries in the message log:
Checking the Dynamic Configuration we can see the respective mail receiver addresses were set
and an email was received successfully:
I hope this blog helps one or the other colleague “out there” implementing mail-to scenarios.
Best regards,
Peter
References: