I have tried to consolidate all information along with the customizable code and issues in this document on the topic.

Please refer following diagram to understand the requirement and applied solution.

emailAtt.jpg      

Please find the sample code below.

Code:


import org.w3c.dom.Document;

import java.util.zip.ZipEntry;

import java.util.zip.ZipOutputStream;

import java.io.OutputStream;

import java.io.ByteArrayOutputStream;

import javax.xml.parsers.DocumentBuilder;

import javax.xml.parsers.DocumentBuilderFactory;

import com.sap.aii.mapping.api.AbstractTransformation;

import com.sap.aii.mapping.api.Attachment;

import com.sap.aii.mapping.api.OutputAttachments;

import com.sap.aii.mapping.api.StreamTransformationException;

import com.sap.aii.mapping.api.TransformationInput;

import com.sap.aii.mapping.api.TransformationOutput;

public void transform(TransformationInput in, TransformationOutput out) throws StreamTransformationException

{

try{

//Getting reference of output attachment

     OutputAttachments outAtt = out.getOutputAttachments();


//Getting reference of output stream to write email package.Read Reference 1

     OutputStream os = out.getOutputPayload().getOutputStream();

//CRLF.Read Reference 2

     String CRLF = “\r\n”;

//Getting Attachment Names (Parametrized java Mapping).Read Reference 11

     String zipName=  in.getInputParameters().getString(“PARAM_ZIPNAME”) //import parameter,Simple Type,xsd:string

         String file1Name=in.getInputParameters().getString(“PARAM_FILE1NAME”)//import parameter,Simple Type,xsd:string

     String file2Name=in.getInputParameters().getString(“PARAM_FILE2NAME”)//import parameter,Simple Type,xsd:string

     String file3Name=in.getInputParameters().getString(“PARAM_FILE3NAME”)//import parameter,Simple Type,xsd:string


//Getting Email Addresses (Parametrized java Mapping).Read Reference 11

     String fromEmail=  in.getInputParameters().getString(“PARAM_FROM”) //import parameter,Simple Type,xsd:string

         String toEmail=in.getInputParameters().getString(“PARAM_TO”)//import parameter,Simple Type,xsd:string

               

//Instantiating DocumentBuilderFactory to parse input stream into Document.Read Reference 3

    DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();

    DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();

    Document doc = dBuilder.parse(in.getInputPayload().getInputStream());

//Adding trace.Read Reference 4                                       

    getTrace().addInfo(“Start of parsing input xml”);


//File1 Parser:Creating a file “file1.txt”

    File1 F1= new File1();       //Instantiating Class File1

    String f1=F1.parseF1(doc);   //Calling parseF1 method of Class File1

  //String file1Name=”file1.txt”;//File Name, provide using parameters as above or hardcode here     

//File2 Parser: Creating another file “file2.txt”

    File2 F2= new File2();        //Instantiating Class File2

    String f2=F2.parseF2(doc);    //Calling parseF2 method of Class File2

   //String file2Name=”file2.txt”;//File Name, provide using parameters as above or hardcode here     

    

//File3: Creating file3.txt             

    String f3=“This is my File 3 Content”; //Fix Content of file3

    //String file3Name=”file3.txt”;//File Name, provide using parameters as above or hardcode here

               

//Zipping file1.txt and file2.txt together. Read Reference 5

     ByteArrayOutputStream baos = new ByteArrayOutputStream();//ByteArrayOutputStream to read/write ZipOutputStream

     ZipOutputStream zos = new ZipOutputStream(baos);//Creating ZipOutputStream

     zos.putNextEntry(new ZipEntry(file1Name));//Creating new entry for file1.txt

     zos.write(f1.getBytes());         //Writing content of file1 into Zip Stream

     zos.putNextEntry(new ZipEntry(file2Name));//Creating new entry for file2.txt

     zos.write(f2.getBytes());         //Writing content of file2 into Zip Stream

     zos.closeEntry();                         //Closing Zip entry

     zos.close();                              //Closing Zip Stream

         

//Zip Name as appear in attachment

  //String zipName=”Notification.zip”;//Zip Name, provide using parameters as above or hardcode here


//Creating Attachment.Read Reference 6

     Attachment newzipAttachment = out.getOutputAttachments().create(zipName, baos.toByteArray());  

//Attaching Zip

     outAtt.setAttachment(newzipAttachment);         


//From and To Email addresses as appear in Email

  //String fromEmail=”files@test.com“;//From Email, provide using parameters as above or hardcode here

//String toEmail=”ambuj.mishra@test.com;others@test.com“; //To Email, provide using parameters as above or hardcode here


//Forming Email Package. Read Reference 7

     String emailPackage=

             “<?xml version=\”1.0\” encoding=\”UTF-8\”?>”+CRLF+

             “<ns:Mail xmlns:ns=\”http://sap.com/xi/XI/Mail/30\”>”+CRLF+

             “<Subject>Delivery notes</Subject>”+CRLF+

             “<From>”+fromEmail+</From>”+CRLF+

             “<To>”+toEmail+</To>”+CRLF+

             “<Reply_To />”+CRLF+

             “<Content_Type>text/plain</Content_Type>”+CRLF+

             “<Content_Disposition>attachment; filename=”+“\””+file3Name+“\””+“</Content_Disposition>”+CRLF+

             “<Content>”+f3+“</Content>”+CRLF+

             “</ns:Mail>”;


//In case, you have incoming attachments in source.

//Read Reference 10.How to read and use them in your code.

    

//How to remove an attachment

        //outAtt.removeAttachment(“Notification.zip”);        


//Writing Email Package

     os.write(emailPackage.getBytes());//Writing Email Package in output stream                  

     os.flush();                       //Flushing output stream

     os.close();                      //Closing output stream

   }

catch (Exception e)

   {

          throw new StreamTransformationException(e.getMessage());

   }     

}

public class File1

{

   public String parseF1(Document doc) throws ParseException {

                return “file 1 content”;     //Read Reference 8 to create flat file using DOM

       }

}

public class File2

{

   public String parseF2(Document doc) throws ParseException {

                return “file 2 content”;    //Read Reference 8 to create flat file using DOM

       }

}

Please read comments/refernces to explore the code. Leave a comment if you have any doubts/questions.

It’s a working code and can be customized easily as per your requirement. I have provided the references, in case you want to customize it. For example, if you want to create a flat file using DOM from incoming xml, you can refer the code in provided link and add those in File1 or File2 class.

You can write above code, directly into ESR and test it for your understanding, as explained below.

Where to write this code?

I always prefer this approach for java mapping as you can test it right away like your graphical mapping.

Write Java Mapping directly in ESR!

MMJM.jpg

How to provide Parameters in mapping?

Please refer following blog, It has all necessary configuration details. And using parameters in java mapping is pretty simple as I showed you in above code.

SAP PI 7.1 Mapping Enhancements Series: Parameterized Message Mappings

Mail Channel Configuration:

Please find below mail channel configuration.

MailChannel.jpg

Test Result:

This is not the exact result of above code. But approach was same.

Version: PI 7.31 (single stack)

EmailAttachments.jpg

Open Ends:

1. I tried to achieve this requirement using following blog post, many times, but couldn’t make it work.

XI Mail Adapter: An approach for sending emails with attachment with help of Java mapping

    Please let me know, if any one have detailed doc on this.



2. While forming Email package, If I am not providing <Content_Type/> and <Content/> tags. My email server is not triggering email.

    I don’t know whether this issue is specific to my email server only or it’s a general case? Please do comment, if you have any information regarding this.



3. Found one testing issue in operation mapping. Please refer http://scn.sap.com/thread/3742233.


Update:

Included Parameterized mapping for file name and email addresses as suggested by Vila.


For 1st and 2nd Open ends point, Stefan has provided some inputs. Please refer comment section for the same.


References for detailed reading:

1. //Output Stream

https://docs.oracle.com/javase/tutorial/essential/io/streams.html

2. //CRLF

http://stackoverflow.com/questions/9260126/what-are-the-differences-between-char-literals-n-and-r-in-java

3. //Document Builder Factory

http://docs.oracle.com/javase/7/docs/api/javax/xml/parsers/DocumentBuilder.html

4. //Adding trace

https://help.sap.com/javadocs/pi/SP3/xpi/com/sap/aii/mapping/api/AbstractTrace.html

5. //Zip Output Stream

http://docs.oracle.com/javase/7/docs/api/java/util/zip/ZipOutputStream.html

6. //Creating Output Attachment

OutputAttachments

7. //Email package

Configuring the Receiver Mail Adapter – Advanced Adapter Engine – SAP Library

8. //Creating flat files using DOM

File Content Conversion in ESR using Java Mapping 

9. Package com.sap.aii.mapping.api

com.sap.aii.mapping.api

10. // Reading and Writing incoming attachments

Attachments zipping during Mapping

11. // Parametrized java mapping

Parameterized Mapping Programs – Managing Services in the Enterprise Services Repository – SAP Library

Parameterized Java Mappings – Managing Services in the Enterprise Services Repository – SAP Library

To report this post you need to login first.

8 Comments

You must be Logged on to comment or reply to a post.

  1. Iñaki Vila

    Hi Ambuj.

    Thank you for sharing!.

    First of all, thank for write down all the references that you have used and the code very well explained.

    I think you are using PI 7.31 or 7.4?, please tell us the PI version that you have test your code.

    A question not only for you, for all the colleagues on the SCN as well,have you thought to trigger you scenario directly with the file adapter?, i think to take the files directly from the sender side could be interesting, to work with attachments that come from the sender side could be helpful.

    Regards.

    (0) 
    1. ambuj mishra Post author

      Thanks for the valuable feedback Vila.

      Version is PI 7.31 single stack.

      In my case: Sender adapter was proxy. From proxy xml, I created 2 flat files using DOM, zipped and attached it as email attachment.

      I wanted to provide a loosely coupled java program structure to the developers, so that it can fit to any type of requirement.

      i think to take the files directly from the sender side could be interesting

      Actually there are few docs with proper codes available on scn regarding this. I will provide the appropriate links here.

      I will update the doc accordingly with these details.

      (0) 
      1. Iñaki Vila

        Hi Ambuj,

        Thank you very much for the clarifications, for you scenario is the best approach.

        I only want to suggest two possible improvements to make loosely coupled your code:

        1. If it is possible to parametrize the name of the attachments. Parametrized mapping?

        2. If it is possible to  parametrize via XML, lookup or parametrized mapping the email addresses.

        Regards.

        (0) 
        1. ambuj mishra Post author

          Thanks for the suggestions.

          1. Definitely, I will include it in the code.

          2. Yes, I have used BRM decision tables, lookup in real time scenario, will include that as well in this doc..

          Update:Included Parametrized mapping for file names and email addresses in the doc.

          (0) 
  2. Stefan Grube

    Hi Ambuj, Your blog is very useful and covers many topics about Java Mapping. For your open ends: 1) If you want to use multipart mime within Mailpackage with binaries, you need to encode them base64 and provide Content-Transfer-Encoding: base64.  2) Content_Type and Content are obligatory elements of the Mailpackage. The mail adapter will fail without those fields. This is an undocumented “feature”. Best Regards Stefan

    (0) 
    1. ambuj mishra Post author

      Thank you for the inputs Stefan. I will include them in the blog.

      23092016 Edit:

      Recently, I got a chance to implement similar kind of solution. For email part, I followed Stefan Grube blog (it is updated now with codes). it totally worked. Thanks.

      (0) 

Leave a Reply