Technology Blog Posts by Members
cancel
Showing results for 
Search instead for 
Did you mean: 
MortenWittrock
SAP Mentor
SAP Mentor
18,939
A few days ago I answered this interesting question by Florian Kube in the Questions & Answers area. It struck me that the solution might be of more general interest, so in this blog post I’m going to expand a bit on my answer.

Florian’s scenario is this: He picks up an email with a sender Mail channel. The email has an XML attachment, and it is the contents of this attachment, he wants to process. He therefore needs to replace the message body with the attached XML document, and then proceed with mapping and so forth.

I’m going to show you how to solve this problem using scripting. The code is written in Groovy, but if your prefer JavaScript, translating it is straightforward.

Methods of the Message class


Access to the body and attachments of a message is provided by the com.sap.gateway.ip.core.customdev.util.Message object, which the runtime passes to your Groovy function. The API documentation available for this interface is available here.

The two methods, we are going to use, are getAttachments and setBody. The former returns a java.util.Map object containing the message’s attachments, and the latter sets a new message body.

Extracting the attachment contents


Let us deal with the attachment first, since that is the more complicated part. The keys of the Map returned by getAttachments are attachment names, and the values are javax.activation.DataHandler objects. The DataHandler objects contain the actual attachment data. Given the scenario, we assume that the Map contains exactly one attachment, but we do not know its key ahead of time.

In order to get the Map’s only value without knowing its associated key, I retrieve the Collection of all the Map’s values and iterate it once. The code looks like this (required import statements not shown):
Map<String, DataHandler> attachments = message.getAttachments()
Iterator<DataHandler> it = attachments.values().iterator()
DataHandler attachment = it.next()

(You could combine the three lines into a single line, if you are so inclined, but that would make the intention of the code less clear, IMHO.)

Setting the message body


The DataHandler class offers a couple of different ways to get at the wrapped data. We are going to use the getContent method, which returns a java.lang.Object object. Why? Because an Object instance is what the setBody method of the Message class expects. Here is the code that replaces the message body:
message.setBody(attachment.getContent())

Putting the pieces together


We are now ready to put it all together. Here is the complete script:
import com.sap.gateway.ip.core.customdev.util.Message
import java.util.Map
import java.util.Iterator
import javax.activation.DataHandler

def Message processData(Message message) {
Map<String, DataHandler> attachments = message.getAttachments()
Iterator<DataHandler> it = attachments.values().iterator()
DataHandler attachment = it.next()
message.setBody(attachment.getContent())
return message
}

In order to use it, put the code in a Script step at the very beginning of your integration flow. After this step, proceed with whatever processing your scenario requires.

How to handle messages with no attachments


Keep in mind that the script assumes that the message has exactly one attachment. If it does not have any attachments, the code will fail. Determining why it fails, is left as an exercise for the reader 🙂

If this assumption is not always met in your particular scenario, you can test for the presence of attachments, by checking whether the Map returned by getAttachments is empty. You do this by calling its isEmpty method as follows:
import com.sap.gateway.ip.core.customdev.util.Message
import java.util.Map
import java.util.Iterator
import javax.activation.DataHandler

def Message processData(Message message) {
Map<String, DataHandler> attachments = message.getAttachments()
if (attachments.isEmpty()) {
// Handling of missing attachment goes here
} else {
Iterator<DataHandler> it = attachments.values().iterator()
DataHandler attachment = it.next()
message.setBody(attachment.getContent())
}
return message
}
19 Comments
rajanikanth_kristam
Product and Topic Expert
Product and Topic Expert

Nice blog. Tells power of Groovy scripting .

Former Member
Nice blog.

 

Best Regards,

Harsh B.
tomvanrooijen
Participant

Hi Morten,

 

I am looking for a way to add an attachment generated in a groovy script (a pdf file) to the header of the message so I can use it in the receiver mailadapter.

So at the start of the script there is no attachment, just a message body with text, which is written to a pdf file using itext.

What I cannot figure out is how to pass this on to the headers. Most of the examples I see work with strings and I guess the pdf file is an object of some sort.

 

Thanks & Regards

Tom

 

MortenWittrock
SAP Mentor
SAP Mentor
Hi Tom

I'm sorry that I didn't get back to you sooner. Just in case you haven't already found a solution: You can add the PDF in Groovy with a few lines of code. I wrote a short blog post about how you do that. You can find it here.

Regards,

Morten
Former Member
0 Kudos
Hi  Morten,

 

Is this possible to update attachment content using script ?  or remove attachment?

 

Thanks and Regards

Eric
jacqueso
Explorer
0 Kudos
Hi Morten,

 

Thanks for the excellent blogs, I am having a strange issue.   As in your previous blogs, in the first step in my Iflow I am using the script to try to create an attachment, to save the payload in that attachment, and then later in my Iflow I want to read that attachment value again to use it as the resulting message body.

 

But for some reason it does not seem like the attachment is being created successfully.  As when I try to read it later down the line, nothing is found.

Any help would be greatly appreciated.
MortenWittrock
SAP Mentor
SAP Mentor
0 Kudos
Hi Jacques

I suggest that your post your question in the Q&A section, using the tag "SAP Cloud Platform Integration for process services". Provide as much detail as is needed. Include, for instance, your script code. Then myself and others will have a closer look.

Regards,

Morten
jacqueso
Explorer
Thanks Morten.

I played around with it a bit more and I got it working using the details you shared in your Blogs.

Thank you so much.  Thanks for the great blogs.  Keep up the good work.

 

Kind Regards
Jacques Otto
MortenWittrock
SAP Mentor
SAP Mentor
0 Kudos
Hi Jacques

I'm very happy to hear that 🙂

Have a nice weekend,

Morten
Former Member
Hello Morten,

How to handle more than one attachments in the script.

 

Thanks,

Mohan
MortenWittrock
SAP Mentor
SAP Mentor
0 Kudos
Hi Mohan

If you have multiple attachments, and you want to replace the payload with one of them, you need some way of identifying that particular attachment. You would need to take a look at the keys in the attachments map, and determine which one to select based on those keys.

Regards,

Morten
Former Member
Hello Morten,

Thanks for the reply.

I am able to send one attachment from SOAP UI to the Iflow and i am able to receive to my email with attachment. Now i am trying to test with multiple attachments...but i am able to receive the only one. can you please tell me how to receive all the attachments?

Thanks,

Mohan
MortenWittrock
SAP Mentor
SAP Mentor
0 Kudos
Hello again

Please post this as a question in the Q&A section, and provide all the details of your situation.

Regards,

Morten
Vijey
Participant
0 Kudos
Hi Experts,

 

Can any one give me the script to read the attachment id 72488 from below response. I need to use this in another call. Thank you.


<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices">
<entry>
<content type="application/xml">
<m:properties>
<d:key>Attachment/attachmentId=72488</d:key>
<d:status>OK</d:status>
<d:editStatus>UPSERTED</d:editStatus>
<d:message>Upserted successfully</d:message>
<d:index m:type="Edm.Int32">0</d:index>
<d:httpCode m:type="Edm.Int32">200</d:httpCode>
<d:inlineResults m:type="Bag(SFOData.UpsertResult)"/>
</m:properties>
</content>
</entry>
</feed>


 

Thanks.
sarabarzano
Explorer
0 Kudos
Hi,

did you manage to solve this?
0 Kudos

Hi 7a519509aed84a2c9e6f627841825b5a 

one step forward. could you help me with this question ?

Mail to SFTP - how to read the attachment name | SAP Community

0 Kudos
Hi 7a519509aed84a2c9e6f627841825b5a

 

We are having issue in reading attachment from mail sender as groovy provided is reading inline embedded images such as signature in the mail also as attachment along with original attachments. Can you please guide us in restricting reading attachment only to original attachment of mail.

Regards,

Sindhuja.

 

 
mathias_rohland
Explorer
0 Kudos

Hi all,

based on what @MortenWittrock proposed I built my slightly enhanced version as we always receive mails with logos which are then also being returned as attachments from the sender mail adapter.

import com.sap.gateway.ip.core.customdev.util.Message;
import java.util.Map;
import java.util.Iterator;
import javax.activation.DataHandler;

def Message processData(Message message) {
    Boolean attachmentOk = false;
    String attachmentContentType = "_N/A_";
    String attachmentName = "_N/A_";
    // GOOGLE MAIL gave back UPPERCASE content types
    String contentTypeXlsx = "APPLICATION/VND.OPENXMLFORMATS-OFFICEDOCUMENT.SPREADSHEETML.SHEET";
    
    Map<String, DataHandler> attachments = message.getAttachments();

    if (attachments.isEmpty()) {
      // Handling of missing attachment goes here
      message.setProperty("attachmentsEmpty", "true");
    } else {
      Iterator<DataHandler> it = attachments.values().iterator();
      
      while (it.hasNext() && !attachmentOk) {
        DataHandler attachment = it.next();

        attachmentName = attachment.getName();
        attachmentContentType = attachment.getContentType().tokenize(";")[0].toUpperCase();
    
        if (attachmentContentType.equals(contentTypeXlsx)) {
            attachmentOk = true;
            message.setBody(attachment.getContent());
        }
      }
    }
    
    if(! attachmentOk) {
        message.setProperty("err500Msg", "FATAL: no attachemnt of type XLSX found.");
    }
    
    message.setProperty("attachmentName", attachmentName);
    message.setProperty("attachmentContentType", attachmentContentType);
    message.setProperty("attachmentOk", attachmentOk);
    
    return message;
}

After my first tests with my private mail account the script didn't work correctly as GMail uses an uppercase representation of the attachment content type. Another 5 min of struggle 🙂

Hope this is being seen as helpful by others.

Regards,
Mathias

UPDATE: had to remove a line of code in the above example that I forgot to delete when I first posted this reply. This was part of an extra debug message I added in the original code but that's of no use in this example - keeping my fingers crossed that this update will not be seen as spam.

zc11
Associate
Associate
0 Kudos

@MortenWittrock @mathias_rohland 

Hi Colleagues

I try to get AS2 generated MDN attachment use code same with blog and found map is empty.

zc11_0-1755074912753.png

zc11_1-1755074954860.png

zc11_2-1755075014074.png

Could u give me some guide?

Thanks