0

I am trying to merge pdf attachments and sending it as email. I am able to merge them but the last pdf always get overwrite all the others and send email as one. When I checked my email attachment size is total of all the attachments. Do anyone have any idea on how to achieve it.

My code

public class mergePdf{

public static void mergePrds(){
     List<Attachment> att = new List<Attachment>();
          String combinedDataAsHex = '';


     for(Attachment a : [Select Id, Body FROM Attachment WHERE ParentId= 'AccountId']){
         System.debug('Attachment ::: '+ a);
         combinedDataAsHex = combinedDataAsHex + EncodingUtil.convertToHex(a.body);

     }

     Blob combinedDataAsBlob = EncodingUtil.convertFromHex(combinedDataAsHex);

     System.debug('combinedDataAsBlob ::: ' + combinedDataAsBlob );
     //Blob combinedDataAsBlob1 = blob.toPDF(combinedDataAsHex);
     //Blob mergePdf = combinedDataAsBlob.toPDF(combinedDataAsBlob);


        Messaging.EmailFileAttachment attach = new Messaging.EmailFileAttachment();
        attach.setContentType('application/pdf');
        attach.setFileName('testPdf.pdf');
        attach.setInline(false);
        attach.Body = combinedDataAsBlob;

        Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
        mail.setUseSignature(false);
        String ccEmail = '[email protected]';
        mail.setToAddresses(new String[] { ccEmail  });
        mail.setSubject('PDF Email Demo');
        mail.setHtmlBody('Here is the email you requested! Check the attachment!');
        mail.setFileAttachments(new Messaging.EmailFileAttachment[] { attach }); 



        // Send the email
        Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });

}
}

1 Answer 1

3

PDF is a binary format that, like most binary formats, simply can't be squashed together directly. It contains magic headers, object graphs, images, compression, and a bunch of other stuff that you really can't parse very well in Apex Code. You can try reading the documentation on parsing it, but you'd probably have better luck using an external library on Heroku, AWS EB, or some other cloud hosting service.

I'm not going to sit down and try to figure out how to make it work, but a feasible implementation in Apex Code might look something like this:

String[] pdfPages = new String[0];
for(Attachment record: [SELECT Body FROM Attachment WHERE ParentId = :accountId]) {
    String pdfFile = EncodingUtil.convertToHex(record.Body);
    // Figure out where the pages are, and extract one at a time
    while(hasMorePages(pdfFile)) {
        pdfPages.add(nextPage(pdfPage));
    }
}
// Now, generate the PDF headers and tables from the pdfPages...

Please note that this is only pseudo-code and not meant to be taken literally. While it's technically possible to do this, I can't imagine it'd be very efficient, and would probably run the risk of running into CPU or heap limits.

4
  • 5
    Nice try, but the above approach has about the same chance as an ice cube not melting in Hades of working. The PDF format is much more complex than what you're thinking for the above to work. Not only does it include a header, it also includes copies of any embedded fonts, jpeg images, security settings and printing instructions. That's part of why there aren't a lot of "free" programs around that will allow you to insert or move pages around in a PDF. It's not like a sequence of HTML pages.
    – crmprogdev
    Commented Nov 24, 2016 at 20:49
  • @crmprogdev Just from looking at the docs, I'd have to agree. That's why I recommended that one would have a better chance using offsite processing, and even then it'd be a lot of work.
    – sfdcfox
    Commented Nov 24, 2016 at 21:37
  • Yes, I've been saying for eons it can't be done via Apex. Sending things out & back to a 3rd party service would be required. If the goal is to only send a single attachment, potentially one could implement a solution like Apex-Zip to wrap the two files in a container.
    – crmprogdev
    Commented Nov 24, 2016 at 21:53
  • 1
    I'm working on this problem right now: 90% solved by writing an Amazon Lambda function on AWS which uses the itextpdf library (developers.itextpdf.com) to do the actual PDF manipulation. You absolutely do not want to roll your own PDF processor without using a library to do the heavy lifting. Using the library, though, it more or less boils down to docToAdd.copyPagesTo(1, docToAdd.getNumberOfPages(), pdfDoc);
    – Aidan
    Commented Nov 25, 2016 at 11:35

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .