+ Start a Discussion
rohit.marathe@tcs.comrohit.marathe@tcs.com 

How to attach external PDF file to the email sent via Apex code

Hi,

The following links shows how to attach pdf and send email using Apex code

http://www.salesforce.com/us/developer/docs/pages/Content/pages_email_sending_attachments.htm

The part in the article given at end of my post reads a pdf and set its content as attachment.But this example only shows how to attach VisualForce page which is renderd as PDF.

 

When I tried same example code with a PDF file hosted on some other server and is public(Say: http://myserver.com/myFile.pdf). The VisualForce page runs without error, but does not give any response. Doesn't Apex attaching external files as attachment with email. If Not is there any other workaround. The problem is I want to attach a PDF which is hosted on some other server and send email using Apex. 

 

 

Messaging.SingleEmailMessage email = new Messaging.SingleEmailMessage();

        // Reference the attachment page and pass in the account ID
        PageReference pdf =  Page.attachmentPDF;
        pdf.getParameters().put('id',(String)account.id);
        pdf.setRedirect(true);

        // Take the PDF content
        Blob b = pdf.getContent();

        // Create the email attachment
        Messaging.EmailFileAttachment efa = new Messaging.EmailFileAttachment();
        efa.setFileName('attachment.pdf');
        efa.setBody(b);

 

Best Answer chosen by Admin (Salesforce Developers) 
forecast_is_cloudyforecast_is_cloudy

Rohit - as I had mentioned in my original post, you can't do what you're trying to do with Apex HTTP callouts either. Apex HTTP callouts currently only support a String/text type response. You can't access binary data (like your PDF) using HTTP callouts as  you're trying to do. Your only option is still to somehow store the PDF inside Salesforce (as an Attachment or Document or Content file) and access it that way. Hope this helps. 

All Answers

forecast_is_cloudyforecast_is_cloudy

Unfortunately you can't currently access binary data hosted on an external site using Apex - either via a direct HTTPRequest callout or indirectly via a VF page that points to the external URL (as you're trying to do). The only option I can think of for you is to store this external PDF in Salesforce (assuming that its static content) either as an Attachment or a Document and then use SOQL to query its content and attach to the email message. 

rohit.marathe@tcs.comrohit.marathe@tcs.com

Thanks forecast_is_cloudy for the quick reply. As you specified in your response it is not directly possible I tried to adapt a diffrent method using HTTP callouts.

I used following code in my Apex Class

 

I am trying to get PDF content as a blob using HTTP callout and creating an email attachment using this Blob. But when I open the email and save the PDF attachment and open it. It opens as blank PDF document always. Not sure either I am missing something or this is not possible at all using Apex code.

Please guide me.

 

Note: in my code replace myemail@myemail.com with your email id so that you will receive an email with PDF.

Thanks.

-----------------Apex Class START----------------------

public class PDFCreator
{
    public PDFCreator()
    {
       
      
       

    }
   
    public void createPDF()
    {
        try
        {    
            // Instantiate a new http object
            Http h = new Http();
            // Instantiate a new HTTP request, specify the method (GET) as well as the endpoint
            HttpRequest req = new HttpRequest();
            req.setEndpoint('http://www.salesforce.com/assets/pdf/datasheets/sales-force-automation.pdf');
            req.setMethod('GET');
            // Send the request, and return a response
            HttpResponse res = h.send(req);
            System.debug('res is>>>>>>'+res);
            System.debug('res.getBody()>>>>>>'+res.getBody());
            Blob pdfContent= Blob.valueOf(res.getBody());
            //System.debug('pdfContent>>>>'+pdfContent);
           
            // Define the email 
   
            Messaging.SingleEmailMessage email = new Messaging.SingleEmailMessage();
           
            String[] toAddresses = new String[] {'myemail@myemail.com'};
           
            Messaging.EmailFileAttachment efa = new Messaging.EmailFileAttachment();
            efa.setFileName('attachment.pdf');
            efa.setContentType('application/pdf');
            efa.setBody(pdfContent);
           
            email.setSubject('Testing PDF attachment');
           
            email.setToAddresses(toAddresses);
            email.setPlainTextBody('Hello');

            email.setFileAttachments(new Messaging.EmailFileAttachment[] {efa});

            // Sends the email 
       
            Messaging.SendEmailResult [] r = Messaging.sendEmail(new Messaging.SingleEmailMessage[] {email});  
            //System.debug('>>>>>Email sent result'+r);


        }
        catch(Exception ex)
        {
            System.debug('>>>>>>>>>>>>>><<<'+ex);
        }

    }
}

-----------------Apex Class END----------------------

 

I have also tried following approach, but this works only with files hosted on salesforce.com server, for other servers (Even after adding them in Remote Site Settings) function never gets executed completely)

public void readPDF()
    {
       

        PageReference pdf = new PageReference('http://www.genius.com/media/GeniusDatasheet.pdf');
       
        Blob b = pdf.getContentAsPDF();
        System.debug('Blob is>>>>>>>'+b);
       
        // Define the email 
   
        Messaging.SingleEmailMessage email = new Messaging.SingleEmailMessage();
       
        String[] toAddresses = new String[] {'youremail@yourdomain.com'}; //{a.CreatedBy.Email};
       
        Messaging.EmailFileAttachment efa = new Messaging.EmailFileAttachment();
        efa.setFileName('attachment.pdf');
        efa.setContentType('application/pdf');
        efa.setBody(b);
       
        email.setSubject('Testing PDF attachment');
       
        email.setToAddresses(toAddresses);
        email.setPlainTextBody('Hello1');

        email.setFileAttachments(new Messaging.EmailFileAttachment[] {efa});

        // Sends the email 
   
        Messaging.SendEmailResult [] r = Messaging.sendEmail(new Messaging.SingleEmailMessage[] {email});  
        //System.debug('>>>>>Email sent result'+r);
    }

 

 

 

 

 

forecast_is_cloudyforecast_is_cloudy

Rohit - as I had mentioned in my original post, you can't do what you're trying to do with Apex HTTP callouts either. Apex HTTP callouts currently only support a String/text type response. You can't access binary data (like your PDF) using HTTP callouts as  you're trying to do. Your only option is still to somehow store the PDF inside Salesforce (as an Attachment or Document or Content file) and access it that way. Hope this helps. 

This was selected as the best answer
rohit.marathe@tcs.comrohit.marathe@tcs.com

Hi forecast_is_cloudy,

Thanks again for the quick reply and explanation. I have accepted your last post as a solution to the problem. But it would be great if you help me in giving some directions if I want to periodically read the files on external server and store them as documents or attachments in Salesforce, without manual upload by SFDC user.

Can we do this using batch apex (I guess we can not as you have already mentioned that Apex can not do this)?

If not can you give me someinformation how we can do this using some third party integration, may be Apex or .NET. or Adobe Flex.

I have refered SFDC forums, documentation and other SFDC related blogs, but yet did not get any solution.

 

forecast_is_cloudyforecast_is_cloudy

Rohit - I would recommend that you develop an external program/application that periodically updates Salesforce with the latest PDF. In other words, instead of a 'pull' model where Salesforce reaches out and grabs the PDF (which is not currently possible to do) you implement a 'push' model whereby an external application pushes the PDF(s) into Salesforce periodically. You can develop such an external application is the language of your choice (Java, .NET, PHP etc.) and then have it use the Salesforce Web Services API to post the PDF as an attachment to Salesforce. Hope this helps. 

rohit.marathe@tcs.comrohit.marathe@tcs.com

Thanks forecast_is_cloudy. I will try to explore in the directions you have given. I hope JAVA or .NET wil alllow me to read external files as blob and store it in Salesforce as attachments using Web services API.

forecast_is_cloudyforecast_is_cloudy

Best of luck!

rvkrvk

Hi rohit, currently working on similar kind of task, could you please let me know your result in getting the pdf from external server and email it as an attachment.

rohit.marathe@tcs.comrohit.marathe@tcs.com

Hi,

Finally instead of pure Apex approach, I used Integration with Java. Here I sent my email body and subject to a java code along with file Id (A refernce Id of pdf file which has been stored on some remote location) using Apex callouts and then I used java code with SFDC partner WSDL integration to send email with this PDF file as an attachment.

So file has been read in javacode instead of Apex.This approach worked well for me.

rvkrvk

thank you so much for replying back. It would be really helpful if could you e send me that java code  to access pdf file from external servers to vk.raavi@gmail.com .

rohit.marathe@tcs.comrohit.marathe@tcs.com

// URLName is complete url of your file

public String dump(String URLName)

{

 

try

{

 

URL u = new URL(URLName);

HttpURLConnection con = (HttpURLConnection) u.openConnection();

String contentType = con.getContentType();

int contentLength = con.getContentLength();

 

if (contentType.startsWith("text/") || contentLength == -1) {

 

thrownew IOException("This is not a binary file.");

}

InputStream raw = con.getInputStream();

InputStream in =

newBufferedInputStream(raw);

 

data = newbyte[contentLength];

 

int bytesRead = 0;

 

int offset = 0;

 

while(offset < contentLength) {

bytesRead = in.read(

data, offset, data.length- offset);

 

if(bytesRead == -1)

 

break;

offset += bytesRead;

}

in.close();

return"Success";

 

}

catch(Exception e) {

e.printStackTrace();

}

return"Failure";

}