7

I am looking for a way to retrieve all attachments from a particular object over a particular time frame.

Can I use Standard SFDC Email functionality to Email attachments retrieved from a SOQL?

I have the SOQL operating properly - I am basically wondering if I can use Apex to run the SOQL and attach the documents to an email.

Here is the SOQL...

SELECT Id FROM Attachment WHERE Parentid IN 
               (Select Id from FF__Custom_Object__c WHERE recordtypeid = '0000000000000' 
                AND Custom_Record_Age_Field_In_Days__c <= 31))
3
  • Ya you can use email templates too with workflows or you can use Outbound email services provided by platform. Commented Nov 29, 2012 at 16:55
  • 1
    Please dont hardcode RecordType Ids .Use Schema describe . Commented Nov 29, 2012 at 16:55
  • 1
    Ultimately, I just want to be able to click a button and somehow, email or otherwise, have all notes and attachments retrieved by the SOQL Commented Nov 29, 2012 at 17:54

2 Answers 2

5

Below is some Apex that will hopefully get you started. I have tested this with a simpler SOQL query and it worked.

Depending on the number and size of the attachments you might run into issues here with the Heap size limits. In an email service context the heap size is 36 MB. Otherwise you will need to stay within 10MB, which isn't very large when dealing with multiple attachments.

// As Mohith suggests, try to avoid hardcording a recordTypeId here
// If you deploy the code between orgs the value can change
Id requiredRecordTypeId = '0000000000000';

List<Attachment> attachments = 
                [SELECT Id, Name, Body, ContentType FROM Attachment 
                 WHERE Parentid IN 
                   (Select Id from FF__Custom_Object__c 
                    WHERE recordtypeid = :requiredRecordTypeId AND 
                          Custom_Record_Age_Field_In_Days__c <= 31))];

Messaging.SingleEmailMessage email = new Messaging.SingleEmailMessage();
String[] toAddresses = new String[] {'[email protected]'};
email.setToAddresses(toAddresses);
email.setSubject('Foo');
email.setPlainTextBody('Bar');

List<Messaging.EmailFileAttachment> emailAttachments = new List<Messaging.EmailFileAttachment>();
for(Attachment att : attachments) {

    Messaging.EmailFileAttachment efa = new Messaging.EmailFileAttachment();
    // You may need to do some work here to figure out the correct file extension
    efa.setFileName(att.Name);
    // Take the blob data from the Attachment and put it on the email.
    efa.setBody(att.Body);
    efa.setContentType(att.ContentType);
    emailAttachments.add(efa);
}

email.setFileAttachments(emailAttachments);
Messaging.sendEmail(new Messaging.SingleEmailMessage[] { email });

It will probably be beneficial for the heap size to express the SOQL query directly in the for loop rather than first assigning it to a list and then looping over the list.

SOQL For Loops Versus Standard SOQL Queries
SOQL for loops differ from standard SOQL statements because of the method they use to retrieve sObjects. While the standard queries discussed in SOQL and SOSL Queries can retrieve either the count of a query or a number of object records, SOQL for loops retrieve all sObjects, using efficient chunking with calls to the query and queryMore methods of the SOAP API. Developers should always use a SOQL for loop to process query results that return many records, to avoid the limit on heap size.

So rather than doing:

List<Attachment> attachments = 
            [SELECT Id, Name, Body, ContentType FROM Attachment 
             WHERE Parentid IN 
               (Select Id from FF__Custom_Object__c 
                WHERE recordtypeid = :requiredRecordTypeId AND 
                      Custom_Record_Age_Field_In_Days__c <= 31))];
// ...
for(Attachment att : attachments) {
    // ...
}

Try:

// ...
for(Attachment att : [SELECT Id, Name, Body, ContentType FROM Attachment 
             WHERE Parentid IN 
               (Select Id from FF__Custom_Object__c 
                WHERE recordtypeid = :requiredRecordTypeId AND 
                      Custom_Record_Age_Field_In_Days__c <= 31))]) {
    // ...
}
1
  • No problem. I see you also mentioned notes. Maybe you could append the note body to the email body, as they are both text based? Commented Nov 30, 2012 at 19:08
3

This answer relates to using the Apex Email API to send the email with your desired attachments. This API is described in the Apex Developers guide here. The following example uses the Single email approach, refer to the docs for the differences between this and the Mass email approach. I have used modified version of your SOQL to test my code, but the same approach applies.

    List<Attachment> attachments = 
        [select Id, Name, Body, ContentType from Attachment 
            where Parentid IN (select Id from Test__c)];
    String currentUserEmail = 
        [select Email from User 
            where Id = :UserInfo.getUserId()].Email;
    Messaging.reserveSingleEmailCapacity(1);
    Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
    mail.setToAddresses(new String[] { currentUserEmail });
    mail.setReplyTo(currentUserEmail);
    mail.setSenderDisplayName('Email Attachments Test');
    mail.setSubject('Latest Attachments from Test__c');
    mail.setBccSender(false);
    mail.setUseSignature(false);
    mail.setPlainTextBody('Attached are the latest attachments to the Test__c object, enjoy!.');
    mail.setHtmlBody('Attached are the latest attachments to the Test__c object, enjoy!.');
    List<Messaging.EmailFileAttachment> emailAttachments = new List<Messaging.EmailFileAttachment>(); 
    for(Attachment attachment : attachments)
    {
        Messaging.EmailFileAttachment emailAttachment = new Messaging.EmailFileAttachment();
        emailAttachment.setBody(attachment.Body);
        emailAttachment.setContentType(attachment.ContentType);
        emailAttachment.setFilename(attachment.Name);
        emailAttachments.add(emailAttachment);                                  
    }
    mail.setFileAttachments(emailAttachments);
    Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });

As per the documentation for the SingleEmailMessage.setFileAttachments method.

A list containing the file names of the binary and text files you want to attach to the email. You can attach multiple files as long as the total size of all attachments does not exceed 10 MB.

RE: Email Templates. I had a quick look at using Email Templates, but the messaging:attachment component does not appear to support bindings for the content and thus I was not sure how you would pass your Attachments into the template. That said I think you may be able to combine the following example with an email template for body via setTemplateId. Let me know if you want this and I'll update the answer.

Hope this helps and enjoy!

3
  • Thank you Andrew! Let me review this - this is exactly what I am looking to do. Commented Nov 30, 2012 at 15:20
  • Your very welcome, hope it hits the spot! Commented Nov 30, 2012 at 18:01
  • hmm, Messaging.reserveSingleEmailCapacity(1); Andrew, I hope you have not pushed something out of my brain I need when this went in :)
    – zjeh
    Commented Nov 30, 2012 at 23:27

You must log in to answer this question.

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