Skip to Content
Technical Articles
Author's profile photo Morten Wittrock

Adding Cloud Integration attachments in code

In a previous blog post of mine, I discussed how you can replace the body of a Cloud Integration message with the contents of an attachment. Tom van Rooijen commented on that post, asking how you can add a binary attachment to a Cloud Integration message, and have that attachment delivered by a receiver mail channel. Since the answer is probably of interest to others, I’m going to describe an approach to solving Tom’s problem in this blog post.

The addAttachmentObject method

Unsurprisingly, the key to adding an attachment to a message is the Message interface. I’ve previously blogged about the methods of this interface, and among them we find the addAttachmentObject method:

public void addAttachmentObject(java.lang.String id, org.apache.camel.Attachment content)

The method expects a string, which is the name of the attachment, and an object of a class implementing the Apache Camel Attachment interface. The Attachment interface is implemented by the DefaultAttachment class located in the org.apache.camel.impl package.

Creating an attachment object

In order to construct a DefaultAttachment object, we need an object wrapping the actual contents of the attachment. In the following, I will assume that we have the contents in a byte array. In Java we have a convenient way of wrapping a byte array: The ByteArrayDataSource class, which implements the DataSource interface. Luckily, this class is available in Cloud Integration. To construct a ByteArrayDataSource object, we need to provide the byte array and a string. The string is the MIME type of the attachment.

Configuring the receiver mail channel

In order for the receiver mail channel to pass our attachment on to the email’s recipient, we need to instruct it to add attachments from the message. To do so, go to the channel’s Connection tab, and make sure that the Add Message Attachments checkbox is selected.

Assembling the pieces

We now know everything we need to know in order to add an attachment in code. In the Groovy code below, the attachment is a PNG image, which I decode from Base64 in order to get a byte array. The binary content can be anything else, of course (but remember to adjust the MIME type accordingly).

import com.sap.gateway.ip.core.customdev.util.Message
import org.apache.camel.impl.DefaultAttachment
import javax.mail.util.ByteArrayDataSource

def Message processData(Message message) {

   // 1: Get the binary attachment content in the form of a byte array
   def imageBytes = 'iVBORw0KGgoAAAANSUhEUgAAAFsAAAALCAIAAACf2mY5AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAEySURBVEhL7ZTBGcMgCIUzlwM5j9NkmQyTPggq+IGml6SH/idFwOcL7Xb+sZAje96YvOtlgJuxLnucuSQ+VUdHSVsqBy1lRkpqx3tORZYxKr/jBt9lIskewSLZTh2pPm/Vv8YtR3r518ODTwauW+n78YYOvJ58nkpxpmKQJK04aemIZBLX3VRda7C2g7N2RJfTfaOnC1CumtFXQnnck41aSeKKtrT5CMg2nhEuUpgnrR2RRwj2gXdgGVV4ySIp6mlPOvraQcOgqG1jR9DAzoVmaHdhgvb+SPGEPQNUoTRJq7jnHUeQ1GaE1t5MAXKkTgNlyM+HkyGANxdOSAbHDfa2jBUWqdFQV36A9sHpOdzuBqskFYbP9f8BKE0yIw9Cl6/9eI/HHYEh8Y/xF3h+Rn6b8/wA8YzyCnrn53gAAAAASUVORK5CYII='.decodeBase64()

   // 2: Construct a ByteArrayDataSource object with the byte array and the content's MIME type
   def dataSource = new ByteArrayDataSource(imageBytes, 'image/png')

   // 3: Construct a DefaultAttachment object
   def attachment = new DefaultAttachment(dataSource)

   // 4: Add the attachment to the message
   message.addAttachmentObject('hello-world.png', attachment)
   
   return message

}

Execute the code in a script step in your integration flow, and the following image will be attached to the message and delivered by the receiver mail channel:

Assigned Tags

      18 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo T. van Rooijen
      T. van Rooijen

      Hello Morten,

       

      Thank you for this write up, I have tested it and it works of course.
      I understand the attachment checkbox in the mail adapter better now.

      The remaining item is to get the pdf that I have created (I think) in groovy into to a base64 format so that the decodeBase64 can do its work.
      The pdf is generated from an example like this:

      import com.sap.gateway.ip.core.customdev.util.Message
      import java.util.HashMap
      import org.apache.camel.impl.DefaultAttachment
      import javax.mail.util.ByteArrayDataSource
      
      import com.itextpdf.text.Document
      import com.itextpdf.text.Paragraph
      import com.itextpdf.text.pdf.PdfWriter
       
      def Message processData(Message message) {
          //Body 
             def body = message.getBody();
            // step 1
          def document = new Document()
          println("Document Created")
       
          // step 2
          PdfWriter.getInstance(document, new FileOutputStream("pdfatt"))
          println("PdfWriter Created")
       
          // step 3
          document.open()
          println("Document Opened")
       
           // step 4
          document.add(new Paragraph("Hello Groovy!"))
          println("Content Added")
       
          // step 5
          document.close()
          println("Document Closed")

      Now how can I get the binary content of this "pdfatt" object so I can generate the message attachment?

      Thanks & regards

      Tom

      Author's profile photo Morten Wittrock
      Morten Wittrock
      Blog Post Author

      Hi Tom

      Base64 is not needed; that was just a convenient way for me to get some binary content into the script.

      What you need, is to get at the binary contents of the PDF generated by the iText library.

      The PDFWriter.getInstance method requires an OutputStream object. One way to solve this is to pass it a ByteArrayOutputStream, which collects bytes into a byte array. So something like the following:

      // Construct a ByteArrayOutputStream object
      def bytes = new ByteArrayOutputStream()
      
      // Your other iText setup goes here
      
      // Pass the ByteArrayOutputStream to the getInstance method
      PdfWriter.getInstance(document, bytes)
      
      // Creating the actual PDF goes here
      
      // After document.close():
      def pdfBinary = bytes.toByteArray()

      At this point, the pdfBinary byte array contains the PDF document, which you can go on to create the attachment with. Remember to import the java.io.ByteArrayOutputStream class.

      Regards,

      Morten

      Author's profile photo Morten Wittrock
      Morten Wittrock
      Blog Post Author

      By the way, remember to change the MIME type to application/pdf 🙂

      Regards,

      Morten

      Author's profile photo Daniel Es
      Daniel Es

      Hi Morten,

      i used the same code above, but unfortunately, the pdf attachement that is sending, is corrupted. Any idea how to deal with it (sending pdf attachment via mail in CPI) ?

       

      Thanks

      Author's profile photo Morten Wittrock
      Morten Wittrock
      Blog Post Author

      Hi Daniel

      Sorry about the late reply. If you still have this issue, please post it in the Q&A section along with all necessary details.

      Regards,

      Morten

      Author's profile photo Athar Iqbal
      Athar Iqbal

      Hi, I am trying to code the scripts in eclipse neon and having problem with import of

      com.sap.gateway.ip.core.customdev.util.Message;

      It doesn't seem to resolve org.apache.camel.Attechment.

      I have tried different version of apache jars but nothing seem to find this package.

      Please help...

      Thanks Athar

      Author's profile photo Morten Wittrock
      Morten Wittrock
      Blog Post Author

      Hi Athar

      Have you added the Script API JAR file to your Eclipse project? It contains the Message interface. The JAR file can be downloaded from https://tools.hana.ondemand.com/#cloudintegration.

      Regards,

      Morten

      Author's profile photo Athar Iqbal
      Athar Iqbal

      Hi Morten,

      Yes,That was the first thing I tried, but as soon as I try o use the Message object, it throws the compilation time error that  org.apache.camel.Attechment cannot be resolved.

      I tried using org.apache.camel.impl.DefaultMessage but it doesn't have the same implementation as Message becuase Message class is an abstract from above.

       

      Athar

      Author's profile photo Morten Wittrock
      Morten Wittrock
      Blog Post Author

      Hello again

      Ah, sorry - I replied too quickly 🙂 To have the Apache Camel classes available in Eclipse, you need to add a Camel JAR. Download the latest version, and add the lib/camel-core-<version>.jar file to your build path.

      Regards,

      Morten

      Author's profile photo Athar Iqbal
      Athar Iqbal

      Hi Morten,

      Thank you so much. It worked. I download Camel Core JAR which has org.apache.camel.impl package.

       

      But I ran into another issue now. What I am trying to do is to develop the scripts and test them in eclipse environment prior to deploying it in SCPI.

      It seems that I cannot use SAP Message object to create a new message and pass it to the function that has the below signature.

      def Message processData(Message message)

      It seems that Message class is an abstract class and cannot be instantiated.

      Thanks

      Athar

      Author's profile photo Morten Wittrock
      Morten Wittrock
      Blog Post Author

      Hi Athar

      Take a look at this blog post by Eng Swee Yeoh.

      Regards,

      Morten

      Author's profile photo Athar Iqbal
      Athar Iqbal

      This is exactly what I was looking for. Thank you so much Morten.

       

      Regards,

       

      Athar

       

      Author's profile photo Jillette Esguerra 
      Jillette Esguerra 

      Is it now allowed to send those attachments in an HTTPS call?

      Author's profile photo Kannan Karunaharan
      Kannan Karunaharan

      Hi Morten,

      Thanks for the great blog, but when i followed the code example i was getting the following error.

      com.sun.mail.smtp.SMTPSendFailedException: 552-5.7.0 This message was blocked because its content presents a potential 552-5.7.0 security issue. Please visit 552-5.7.0 https://support.google.com/mail/?p=BlockedMessage to review our 552 5.7.0 message content and attachment content guidelines. f192sm28347935wmg.30 - gsmtp

      So, i tried to send the attachment as in the following way and it worked.

      Step  1: I set the "binary attachment content in the form of a byte array" to message.SetBody(bytearray)

      Step2:

      Author's profile photo Morten Wittrock
      Morten Wittrock
      Blog Post Author

      Hi Kannan

      Nice approach. The error is probably specific to Google and your particular attachment.

      Regards,

      Morten

      Author's profile photo Aman Raj
      Aman Raj

      Hi Morten,

      I need to convert a Base64 image to image URL in SAP CPI, I have tried Javascript but Blob and Uint8Array not supported in javascript od SAP CPI.

      Can you please tell me if we can do that using Groovy, I have already used groovy to create the binary image from base64 image data, but don't know how to create image URL from that.

      Kindly help on this.

      Regards,

      Aman Raj

      Author's profile photo Tarakaram N
      Tarakaram N

      Hi Morten,

      That's a great blog!

      I have a requirement to handle SOAP response which is MIME as attachment.

      Can we achieve..?

       

      Regards,

      NTR

      Author's profile photo Shameer Shaik
      Shameer Shaik

      Hello Morten, I am trying to post binary data(PDF/GIF/PPTX etc) from

      Postman->CPI>AzureBlobstorage. Iam using HTTP receiver adapter to post message to azure blob storage. I see the content size gets created correctly. But there is no content available or gets corrupted while I download from azure blob storage. I have not used any scripts.Can you provide any insights