0

I have an Apex class that contains @future annotation method to send email. A Visualforce page is rendered as pdf and is sent as an email. I'm getting an exception in test class-

System.EmailException: SendEmail failed. First exception on row 0; first error: REQUIRED_FIELD_MISSING, No body supplied for the file attachment.: [fileAttachments]

Controller code(@future annotated)-

    PageReference pdf =  Page.ReceiptPrintPage;                       
        pdf.getParameters().put('AccId',parameter1); 
        pdf.getParameters().put('year',String.valueOf(parameter2));
        pdf.setRedirect(true);
        // Take the PDF content            
        Blob b;
      try{
            b = pdf.getContentAsPDF();
        }catch(Exception ex){
          System.debug('ex'+ex);
      }    

        // Create the email attachment
        String filename = parameter3 + '_receipt_' + parameter2 + '.pdf'; 
      Messaging.EmailFileAttachment efa = new Messaging.EmailFileAttachment();
        //Messaging.EmailFileAttachment.setContentType(param1)                
        efa.setFileName(filename);
        efa.setBody(b);                               

        // Sets the paramaters of the email
        String subject = 'Recurring Donations Receipt for the Fiscal Year - ' + parameter2;                                                   
        body = 'Hello';
        email.setSubject(subject);
        email.setToAddresses(new String[] {parameter4});
        email.setPlainTextBody(body);           
      email.setFileAttachments(new Messaging.EmailFileAttachment[] {efa});                                             
        // Sends the email
        Messaging.SendEmailResult [] r = Messaging.sendEmail(new Messaging.SingleEmailMessage[] {email});

Test code-

    PageReference pdf =  Page.ReceiptPrintPage;
    pdf.getParameters().put('AccId',a1.Id); 
    pdf.getParameters().put('year',String.valueOf(fiscalYear));
    pdf.setRedirect(true);                
    Blob b;
    try{
        System.debug('before test content');      
        //b = pdf.getContentAsPDF();
        b = pdf.getContent();
    }catch(Exception ex){
        System.debug('ex'+ex);
    }  

    Messaging.EmailFileAttachment efa = new Messaging.EmailFileAttachment();
    String filename = 'Receipt_' + fiscalYear + '.pdf';                                  
    efa.setFileName(filename);
    efa.setBody(b);                                   

    Messaging.SingleEmailMessage email = new Messaging.SingleEmailMessage();
    String body = 'Testing Email';
    String subject = 'Recurring Donations Receipt for the Fiscal Year - ' + fiscalYear; 

    email.setSubject(subject);
    email.setToAddresses(new String[] {'[email protected]'});                
    email.setPlainTextBody(body);           
    email.setFileAttachments(new Messaging.EmailFileAttachment[] {efa});                                           
    Messaging.SendEmailResult[] r = Messaging.sendEmail(new Messaging.SingleEmailMessage[] {email});              

How can I set body for file attachment?

1
  • Please phrase your questions as questions. That is to say, your question will be better formed (more on topic according to the help center) if you ask something rather than suggest to others that they help you.
    – Adrian Larson
    Commented Oct 27, 2017 at 13:19

2 Answers 2

1

Your code is correct.
The issue you are having is that pdf.getContent(); is throwing an exception and the Blob variable b is null by the time efa.setBody(b); is executed (because it was never initialised).

Edit with what I mean, including the suggestion of @Rahul Sharma/Bob ;)

If you put the logic outside, its easier to cover with a test, and then you just leave the send-message out. something like...

private /*or public*/ static Messaging.SingleEmailMessage getEmailMessage(String paramAccountId, String paramYear, String paramFilePrefix, String paramToAddress);
    PageReference pdf =  Page.ReceiptPrintPage;
    pdf.getParameters().put('AccId',paramAccountId);
    pdf.getParameters().put('year',paramYear);
    pdf.setRedirect(true);
    // Take the PDF content
    Blob b;
    try {
        if (Test.IsRunningTest()) {
            b = Blob.valueOf('My awesome pdf, but txt');
        } else {
            b = pdf.getContentAsPDF();
        }
    } catch(Exception ex){
        System.debug('ex'+ex);
        // actually do something about it, like sending an error message to an admin or opening a ticket or something
    }


    // Create the email attachment
    String filename = paramFilePrefix + '_receipt_' + paramYear + '.pdf';
    Messaging.EmailFileAttachment efa = new Messaging.EmailFileAttachment();
    //Messaging.EmailFileAttachment.setContentType(param1)
    efa.setFileName(filename);
    efa.setBody(b);

    // Sets the paramaters of the email
    String subject = 'Recurring Donations Receipt for the Fiscal Year - ' + paramYear;
    body = 'Hello';
    email.setSubject(subject);
    email.setToAddresses(new String[] {paramToAddress});
    email.setPlainTextBody(body);
    email.setFileAttachments(new Messaging.EmailFileAttachment[] {efa});

    return email;
}

Having in the @future method something like

Messaging.SendEmailResult [] r = Messaging.sendEmail(new Messaging.SingleEmailMessage[] {getEmailMessage(parameter1, String.valueOf(parameter2), parameter3, paramater4)});

and in the test method something like

Messaging.SingleEmailMessage toBeTested = getEmailMessage(parameter1, String.valueOf(parameter2), parameter3, paramater4);

System.assertEquals(new List<String>{parameter4}, toBeTested.getToAddresses());
System.assertNotEquals(null, toBeTested.getFileAttachments());
System.assertEquals('Recurring Donations Receipt for the Fiscal Year - ' + String.valueOf(parameter2), toBeTested.getSubject());
....
7
  • So how to initialize? Yes you are right that pdf.getContent(); is throwing exception. What is the workaround for that? Commented Oct 27, 2017 at 12:58
  • The code you pasted is part of your test method or part of your @future method? Commented Oct 27, 2017 at 13:06
  • It is part of test method. I'll edit the question and put @future method. Please check the update in a while. Commented Oct 27, 2017 at 13:09
  • in the test code you could replace b = pdf.getContent(); by b = Blob.valueOf('Testing 1 2 3'). But if you really want to make a test, you should do a method that returns the email, and then in the test, make sure that the content of the email is what you expect and so on. Then in the method, use what @Rahul Sharma says, to generate the blob of 'Testing 1 2 3' only for test context, and then you could check for that in your asserts Commented Oct 27, 2017 at 13:47
  • Sorry, but I didn't understand that. "do a method that returns the email", means? In controller class you mean? Please elaborate in form of answer if possible. Commented Oct 27, 2017 at 18:38
0

Thanks a lot for providing solutions. I finally found the perfect solution to my stated problem. As suggested by Mohith Shrivastava here.

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