Skip to Content
Technical Articles
Author's profile photo Dilip Kumar Krishnadev Pandey

File to Mail Attachment Scenario

Overview:

This blog’s main objective is to consolidate different approaches to address below cases using PI/PO scenarios:

  • How to send a mail having a FlatFile as a mail-attachment
  • How to encrypt/sign the attachment on runtime before sending it to the mail
  • How to set mail-attachment name as of original file name without using any CustomAdpaterModule
  • How to set static mail-attachment name

Following business requirement was the motive of this exercise:

  • Read the file from SAP-R3 directory(NFS) or FTP or SFTP
  • Encrypt it using external-party’s PGP-Pub key and sign it using own passphrase
  • and send the encrypted/signed content as an attachment to a mail-id. The attachment should have original file name.

Approach-01: Set original FileName as mail-AttachmentName with use of “Mail Package”

  • Use “Sender FILE CC (Communication Channel)” configuration to read the file from directory and applying Module Bean ‘PGPEncryption’ for Encryption/Signing of the file content
  • Use “Receiver MAIL CC” configuration to send the mail. Here “Mail Package” is been used.
  • And Use Java-Map in ESR (Enterprise Service Repository) to prepare “Mail Package XML”
  • Below is the Java-Map program to prepare “Mail Package XML”:
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;

import com.sap.aii.mapping.api.AbstractTrace;
import com.sap.aii.mapping.api.DynamicConfiguration;
import com.sap.aii.mapping.api.DynamicConfigurationKey;
import com.sap.aii.mapping.api.StreamTransformation;
import com.sap.aii.mapping.api.StreamTransformationConstants;
import com.sap.aii.mapping.api.StreamTransformationException;

public class FileToMailAttachment implements StreamTransformation{

	private Map param;
	public void setParameter(Map map) {
		param = map;
		if (param == null) {
			param = new HashMap();
		}
	}
	
	private static AbstractTrace trace = null;	
	public void execute(InputStream in, OutputStream out) throws StreamTransformationException {
		try {
			/**
			 * Required MAP_jar files: aii_map_api.jar
			
			 * Purpose of this JavaMap:
			 * 	Once File-Sender-Adapter reads file, sending this file as an attachment to Receiver Mail Adapter using MailPackage

			 * Functionality of This JavaMap:
			 * 1. Get FileName from ASMA DynamicConfiguration Variable
			 * 2. To just copy InputStream(FileContent read by FileAdapter) to String
			 * 3. Prepare "MailPackage_XML" having dynamic attachment name
			 * 4. Send MailPackage_XML to OutputStream
			 */
			trace = (AbstractTrace)param.get(StreamTransformationConstants.MAPPING_TRACE);
			trace.addInfo("Start of JavaMap class FileToMailAttachment()");
					   
			//1. Get FileName from ASMA DynamicConfiguration Variable
			String strFileName = "";
		    DynamicConfiguration conf = (DynamicConfiguration)param.get("DynamicConfiguration");
			DynamicConfigurationKey key = DynamicConfigurationKey.create("http://sap.com/xi/XI/System/File","FileName");
			strFileName = conf.get(key);	//to get the value from the 'key'
			trace.addInfo("FileName: "+ strFileName );	 	
			
			//2. To just copy InputStream(FileContent read by FileAdapter) to String
			byte[] bytes = new byte[in.available()];	
			in.read(bytes);
			String fileContent= new String(bytes, "UTF-8");
			
			//3. Prepare "MailPackage_XML" having dynamic attachment name
			String subjectMail = "FileToMail_EncSigned_TEST";
			String fromMailId = "MiddlewareMail@xyz.com";
			String toMailId = "testMail@ghj.com";			
			String mailPackage = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"+ "\r\n" +
			"<ns:Mail xmlns:ns=\"http://sap.com/xi/XI/Mail/30\"> "+ 
				"<Subject>"+ subjectMail +"</Subject>" +
				"<From>"+ fromMailId +"</From>"+
				"<To>"+ toMailId +"</To>"+
				"<Reply_To />"+
				"<Content_Type>multipart/mixed;boundary = --AaZz</Content_Type>"+
				"<Content>"+
					"----AaZz"+
					"\r\nContent-Type: text/plain; charset=UTF-8" + "\r\n" +
					"Content-Disposition: inline" + "\r\n" + "\r\n" +
					"The attachment \""+ strFileName  + "\" is a encrypted/signed document." + "\r\n" +
					"----AaZz" + "\r\n" +
					"Content-Type: application/xml; name=" + strFileName  + "\r\n" +
					"Content-Disposition: attachment; filename=" + strFileName + "\r\n" + 
					"\r\n" + fileContent +  "\r\n"+			  		
			  	"</Content>"+
			"</ns:Mail>";
			
			//4. Send MailPackage_XML to OutputStream
			out.write(mailPackage.getBytes(Charset.forName("UTF-8")));
			    
			trace.addInfo("End of JavaMap class FileToMailAttachment()");			
		}catch(Exception e){
			trace.addInfo("Exception in JavaMap FileToMailAttachment(): " + e.getMessage());
		}
	}
	/*
	public static void main(String[] args) {
		try {
			String filePath = "C:\\Users\\xyz\\Desktop\\TEST\\";				
			String Fnm = "Input_Sample1.csv";
			String inputFile = filePath + Fnm;	
			String outputFile = filePath + "Output_" + Fnm ;

			FileToMailAttachment myClass = new FileToMailAttachment();
			FileInputStream in = new FileInputStream(inputFile);
			FileOutputStream out = new FileOutputStream(outputFile);
			myClass.execute(in, out);
		}catch(Exception e){
			e.printStackTrace();
		}
	}*/
}

Following screen displays “Sender FILE CC” configuration:

And on this “Sender FILE CC”, apply Module Bean “PGPEncryption” as follows, where

  • applySignature =true     This is to Sign the FileContent using own passphrase
  • keyRootPath = <>            The path where partner’s PGP_Public_Key and own PrivatePublic_Key is present
  • ownPrivateKey = <>       Own PrivatePublic_Key file name
  • partnerPublicKey =<>    Partner’s PGP_Public_Key file name
  • pwdOwnPrivateKey=<> Own passphrase/password

And if we want to send the raw file content (without Encryption/Signing), then Only use default Module Bean ‘CallSapAdapter’

Following screen displays “Receiver MAIL CC” configuration:

Use of IMAP4 is been shown here, We can used SMTP too.

In TAB ‘General’ TAB, provide Mail Server URL and check checkBox ‘Use Mail Package’

In TAB ‘Advanced’ TAB, check CheckBox ‘Use Adapter-Specific Message Attributes’

In TAB ‘Module’, default module selection

Output/TEST reference: Following is the test screen, where, using above PI/PO interface configuration, the file “Sample.txt” was been read from directory, its been been encrypted/signed  and using JavaMap, respective ‘Mail-Package’ was been prepared and this was sent to Receiver-Mail-CC which result into below Mail-Screen:

 

Approach-02: Set static mail-AttachmentName (without use of “Mail Package”) 

  • We can design a simple pass through PI/PO scenario (without ESR) to achieve above requirement’s objective, but when we want to set STATIC attachment name
  • Use “Sender FILE CC” to read the files from SAP-R3 directory.
  • Use “Receiver MAIL CC” to encrypt/sign the file content and send this Encrypted/Signed content as an attachment to the mail-id.
  • On “Receiver MAIL CC”, use Module Bean “MessageTransformBean” to rename attachment to a fix static name.
  • On “Receiver MAIL CC”, use Module Bean “PGPEncryption” to perfom Encryption/Signing of the payload/FileContent
  • Note: Here, if we do not use “PGPEncryption” Module on “Sender FILE CC” because it sends payload to “Receiver MAIL CC” as a HTML content having BODY with Encrypted/Signed string

Following screen displays “Receiver MAIL CC” configuration: 

And on this “Receiver MAIL CC“, apply Module Bean “MessageTransformBean” as follows:

And on this “Receiver MAIL CC“, apply Module Bean “PGPEncryption” as follows in given sequence if we want to encrypt/sign the file Content:

Output/TEST reference:

 

Approach-03: Set original FileName as mail-AttachmentName (without use of “Mail Package”)

  • Here, we create a custom JavaAdapterModule to set dynamic mail-AttachmentName as of original FileName.
  • Most of configuration (of PI/PO pass-through interface) will remain same as of above Approach-02, except one setting, which is, that,
  • in Receiver-Mail-CC, in Module TAB, instead of using MessageTransformBean, we use custom module
    • Replace “AF_Modules/MessageTransformBean” with “localejbs/setDynmMailAtchmnt” in “Processing Sequence”
    • Note: There is no “Module Configuration” parameter for custom module “localejbs/setDynmMailAtchmnt”
  • For detailed custom JavaAdapterModule creation step, below blog link can be referred:
  • And as per “Approach-03” requirement, following Java-code can be referred:
package com.sap.adaptermodule;
import java.rmi.RemoteException;
import java.util.ArrayList;
import javax.ejb.EJBException;
import javax.ejb.SessionBean;
import javax.ejb.SessionContext;
import javax.ejb.TimedObject;
import javax.ejb.Timer;
import com.sap.aii.af.lib.mp.module.ModuleContext;
import com.sap.aii.af.lib.mp.module.ModuleData;
import com.sap.aii.af.lib.mp.module.ModuleException;
import com.sap.aii.af.service.auditlog.Audit;
import com.sap.engine.interfaces.messaging.api.Message;
import com.sap.engine.interfaces.messaging.api.MessageKey;
import com.sap.engine.interfaces.messaging.api.MessagePropertyKey;
import com.sap.engine.interfaces.messaging.api.auditlog.AuditLogStatus;

public class setDynmMailAtchmntBean implements SessionBean, TimedObject {

	/* (non-Javadoc)
	 * @see javax.ejb.SessionBean#ejbActivate()
	 */
	public void ejbActivate() throws EJBException, RemoteException {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see javax.ejb.SessionBean#ejbPassivate()
	 */
	public void ejbPassivate() throws EJBException, RemoteException {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see javax.ejb.SessionBean#ejbRemove()
	 */
	public void ejbRemove() throws EJBException, RemoteException {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see javax.ejb.SessionBean#setSessionContext(javax.ejb.SessionContext)
	 */
	public void setSessionContext(SessionContext arg0) throws EJBException,
			RemoteException {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see javax.ejb.TimedObject#ejbTimeout(javax.ejb.Timer)
	 */
	public void ejbTimeout(Timer arg0) {
		// TODO Auto-generated method stub

	}

	public void ejbCreate() throws javax.ejb.CreateException {
		
	}
	
	private SessionContext myContext;
	MessageKey amk = null;	
	public ModuleData process(ModuleContext moduleContext, ModuleData inputModuleData) throws ModuleException{	    
		Object obj = null;
	    Message msg = null;
	    try
		{
			obj = inputModuleData.getPrincipalData();
		    msg = (Message) obj;
		    amk = new MessageKey(msg.getMessageId(),msg.getMessageDirection());	
		    Audit.addAuditLogEntry(amk, AuditLogStatus.SUCCESS, "Start of Custom-JavaAdapterModule JNDI setDynmMailAtchmnt ................");
		    
		    //1. Read "FileName" MessageProperty  		
		    String sourceFileName = "";	
			for (MessagePropertyKey key : msg.getMessagePropertyKeys()) {
				String propertyName = key.getPropertyName();			//"FileName"
				String propertyNamespace = key.getPropertyNamespace(); 	//"http://sap.com/xi/XI/System/File"	
				String propertyStr = propertyName + "_" + propertyNamespace;				
				if(propertyStr.indexOf("FileName_http://sap.com/xi/XI/System/File") > -1){
					sourceFileName = msg.getMessageProperty(key);		//"01.zip"
					Audit.addAuditLogEntry(amk, AuditLogStatus.SUCCESS, ("MessageProperty " + (propertyName + " " + propertyNamespace + " " + sourceFileName)));
					break;
				}
			}	

			//3. Set Dynamic mail-AttachmentName in MessageProperty			
			MessagePropertyKey sKey1 = new MessagePropertyKey("Part[0].Content-Description","http://sap.com/xi/XI/System/Mail");
			msg.setMessageProperty(sKey1, sourceFileName);
			Audit.addAuditLogEntry(amk, AuditLogStatus.SUCCESS, ("Setting MessageProperty as: Namespace=http://sap.com/xi/XI/System/Mail Name=Part[0].Content-Description Value=" + sourceFileName));	  
			
			MessagePropertyKey sKey2 = new MessagePropertyKey("Part[0].Content-Disposition","http://sap.com/xi/XI/System/Mail");
			msg.setMessageProperty(sKey1, ("attachment; filename=\"" + sourceFileName + "\""));
			Audit.addAuditLogEntry(amk, AuditLogStatus.SUCCESS, ("Setting MessageProperty as: Namespace=http://sap.com/xi/XI/System/Mail Name=Part[0].Content-Disposition Value=" + ("attachment; filename=\"" + sourceFileName + "\"")));	  
			
			MessagePropertyKey sKey3 = new MessagePropertyKey("Part[0].Content-Type","http://sap.com/xi/XI/System/Mail");
			msg.setMessageProperty(sKey1, "text/html; charset=utf-8");
			Audit.addAuditLogEntry(amk, AuditLogStatus.SUCCESS, ("Setting MessageProperty as: Namespace=http://sap.com/xi/XI/System/Mail Name=Part[0].Content-Type Value=text/html; charset=utf-8"));	  
					
			inputModuleData.setPrincipalData(msg);	//set msg property again as principal data			
			Audit.addAuditLogEntry(amk, AuditLogStatus.SUCCESS, "End of Custom-JavaAdapterModule JNDI setDynmMailAtchmnt ..................");	  
			return inputModuleData;	  
		}catch (Exception e) {
		      ModuleException me = new ModuleException(e);
		      throw me;
	    }	   
	}
}

 

Thanks for reading it. Hope, this blog has helped you….

Assigned tags

      2 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Samir Lambe
      Samir Lambe

      Hi,

      Nice blog!!!

      Got similar requirement but need to trigger email with zip as an attachment and file must be password protected...looking forward for your assistance.

      Cheers!

      Sam.

      Author's profile photo Dilip Kumar Krishnadev Pandey
      Dilip Kumar Krishnadev Pandey
      Blog Post Author

      Hi Samir,

      Zip attachment using JavaMap (Mail-Package), I haven't tried yet.

      Without mail-package you can do it, only retaining original file name as an attachment may not be possible with std. config. sorry couldn't help u.

      Thanks & Regards,

      Dilip