Powered By Blogger

Saturday 9 August 2014

Handling Inline Images in Salesforce Inbound Email

One of the Salesforce powerful feature is Inbound Email Services. Using this, you can send an email to Salesforce and process the email body as you want. Inbound email handler class allows you to access email’s plain text body as well as html body.

One issue that I came across was, none of the existing method can handle your inbound email’s inline images. I searched community a lot and realized that, too many people had the same issue but they never find any solution, so I thought to pick it from there.

Issue:
You want to write email’s HTML body in a Rich Text area field and your email has inline images. Now, when you send this, inbound email will lost those images references and your body will say “Inline Image XXXXX”.

More Detail:
I have created an email service in my org. It only listens inbound email and put the email’s HTML body in a rich text area field on lead.

global class POCEmailHandler implements Messaging.InboundEmailHandler {
    
    //Method to process email 
    global Messaging.InboundEmailResult handleInboundEmail(Messaging.InboundEmail email, Messaging.InboundEnvelope envelope) {
        Messaging.InboundEmailResult result = new Messaging.InboundEmailresult();
        
        //Create a New Lead record
        Lead lead = new Lead();
        lead.LastName = 'Inbound Lead';
        lead.Email = email.fromAddress;
        lead.Company = 'N/A';
        lead.HTML_Body__c = email.htmlBody;
        
        //Insert record
        insert lead;
    }
}


Now I sent below email to this email service. Inbound handler class processed it and a new lead was created in system.



This lead was created in system. Notice the HTML Body field.












Inline image didn’t came in the HTML body.

Reason:
Salesforce process inline images as binary attachments. When you send an email having inline images, it doesn’t come as a part of body, but it comes as binary attachment. From here, you will have to put your own logic to place the inline images back in HTML Body.

Resolution:

1.       Process binary attachments and see, which attachment came as a part on inline image. Create an attachment record for each image. Below code is to create a map with the inline image name and its related attachment record.


//Create a list of attachments
        Map< String, Attachment > mapAttachments = new Map< String, Attachment >(); 
        
        //Attachments
        for(Messaging.InboundEmail.BinaryAttachment bA : email.binaryAttachments) {
            System.debug(bA);
            for(integer i = 0; i < bA.headers.size(); i++) {
                
                //Header Value
                String headerValue = bA.headers[i].value;
                if(headerValue.startsWith('ii') || headerValue.startsWith('< image')) {
                    headerValue = headerValue.replaceAll('<', '').replaceAll('>', '');
                    mapAttachments.put(headerValue, new Attachment(Name = bA.fileName, body = bA.body, 
                                                    ParentId = lead.Id, ContentType = bA.mimeTypeSubType));
                }
            }
        }



2.       Now process HTML body content and get all the places where actual Inline Image was replaced with blank space and update these instances with the attachment link.
//Process inline images and update the HTML Body
        for(String headerValue : mapAttachments.keySet()) {
    
            //Reference Link
            String refLink = '/servlet/servlet.FileDownload?file=' + mapAttachments.get(headerValue).Id;
            lead.HTML_Body__c = lead.HTML_Body__c.replaceAll('cid:' + headerValue, refLink);
        }
        update lead;
 


Updated code will look like this.
global class POCEmailHandler implements Messaging.InboundEmailHandler {
    
    
global class POCEmailHandler implements Messaging.InboundEmailHandler {
    
    //Method to process email 
    global Messaging.InboundEmailResult handleInboundEmail(Messaging.InboundEmail email, Messaging.InboundEnvelope envelope) {
        Messaging.InboundEmailResult result = new Messaging.InboundEmailresult();
        
        //Create a New Lead record
        Lead lead = new Lead();
        lead.LastName = 'Inbound Lead';
        lead.Email = email.fromAddress;
        lead.Company = 'N/A';
        lead.HTML_Body__c = email.htmlBody;
        
        //Insert record
        insert lead;
        
        //Create a list of attachments
        Map< String, Attachment > mapAttachments = new Map< String, Attachment >(); 
        
        //Attachments
        for(Messaging.InboundEmail.BinaryAttachment bA : email.binaryAttachments) {
            System.debug(bA);
            for(integer i = 0; i < bA.headers.size(); i++) {
                
                //Header Value
                String headerValue = bA.headers[i].value;
                if(headerValue.startsWith('ii') || headerValue.startsWith('< image')) {
                    headerValue = headerValue.replaceAll('<', '').replaceAll('>', '');
                    mapAttachments.put(headerValue, new Attachment(Name = bA.fileName, body = bA.body, 
                                                    ParentId = lead.Id, ContentType = bA.mimeTypeSubType));
                }
            }
        }
        
        //Insert
        insert mapAttachments.values();
        
        //Process inline images and update the HTML Body
        for(String headerValue : mapAttachments.keySet()) {
    
            //Reference Link
            String refLink = '/servlet/servlet.FileDownload?file=' + mapAttachments.get(headerValue).Id;
            lead.HTML_Body__c = lead.HTML_Body__c.replaceAll('cid:' + headerValue, refLink);
        }
        update lead;
        
        return result;
    }
}




Now send the same email to Salesforce email address and see the result.













Don't  miss DF-14. See you there.
http://bit.ly/df14infblog
Join us in the Developer Zone at Dreamforce 2014 | Training, Talks & MoreSalesforce
Join Salesforce Developers from around the world in the Developer Zone at Dreamforce 2014. Learn new skills through interactive sessions and hands-on training. Immerse yourself in the tools and knowledge you need to build better, faster, and deliver more. For a limited time developers can register for Dreamforce at a special rate of $899.