0

I was wondering if there is a simple to solve my issue, previously in apex one of the automation process was adding attachments from email, please see the code below.

    private void addAttachmentsToContract(Contract contract) {
        Attachment[] attachments = new List<Attachment>();
        for (integer i = 0; i < email.binaryAttachments.size(); i++) {
            Attachment attachment = new Attachment(
                    ParentId = contract.Id,
                    Name = email.binaryAttachments[i].Filename,
                    Body = email.binaryAttachments[i].Body
            );
            attachments.add(attachment);
        }
        insert attachments;
    }

Is there a way to easily convert this code to add Files aka ContentDocument?

1
  • 1
    I wrote a library to do this, which might be a good example.
    – David Reed
    Oct 3 '18 at 14:39
7

Lets add two methods first, one to create a ContentVersion record:

private ContentVersion createContentVersion(String name, Blob body)
    ContentVersion contentVersion = new ContentVersion();
    contentVersion.ContentLocation = 'S'; // S = Stored in Salesforce
    contentVersion.PathOnClient = name;
    contentVersion.Title = name;
    contentVersion.VersionData = EncodingUtil.base64Decode(body);
    return contentVersion;
}

And one to create a ContentDocumentLink record:

private ContentDocumentLink createContentDocumentLink(Id contentDocumentId, Id parentId){
    ContentDocumentLink contentDocumentLink = new ContentDocumentLink();
    contentDocumentLink.ContentDocumentId = contentDocumentId;
    contentDocumentLink.LinkedEntityId = parentId;
    contentDocumentLink.ShareType = 'I'; // Inferred permission
    contentDocumentLink.Visibility = 'InternalUsers';
    return contentDocumentLink;
}

The former will result in a ContentDocument being created with the name and body of the email attachment stored in the related ContentVersion, whereas the latter will set up sharing for internal users with permissions that are inferred from the parent record. For more information on the fields populated and their options:

https://developer.salesforce.com/docs/atlas.en-us.object_reference.meta/object_reference/sforce_api_objects_contentversion.htm

https://developer.salesforce.com/docs/atlas.en-us.object_reference.meta/object_reference/sforce_api_objects_contentdocumentlink.htm

Next, to modify your existing code to use these two methods:

private void addAttachmentsToContract(Contract contract) {
    ContentVersion[] contentVersions = new List<ContentVersion>();
    for (integer i = 0; i < email.binaryAttachments.size(); i++) {
        ContentVersion contentVersion = createContentVersion(email.binaryAttachments[i].Filename, email.binaryAttachments[i].Body);
        contentVersions.add(contentVersion);
    }
    insert contentVersions;

    List<ContentDocumentLink> contentDocumentLinks = new List<ContentDocumentLink>();
    contentVersions = [SELECT Id, ContentDocumentId FROM ContentVersion WHERE Id IN :contentVersions];
    for(ContentVersion contentVersion : contentVersions){
        ContentDocumentLink contentDocumentLink = createContentDocumentLink(contentVersion.ContentDocumentId, contract.Id);
        contentDocumentLinks.add(contentDocumentLink);
    }
    insert contentDocumentLinks;
}
4
  • wow! didn't expect that :) so nice and I am very thankful for you help! I have just changed void methods as they return value and parameters in createContentVersion method as email.binaryAttachments[i].Body returns a blob (I have removed also encoding as the conversion is not needed??)
    – Tomek
    Oct 3 '18 at 18:26
  • Happy to help! :-) The Content objects can be a bit of a pain to figure out, I find. I thought Base64 encoding was required, but you may be right - always new things to learn! Thanks for the corrections - I'll update the answer. :-) Oct 4 '18 at 7:34
  • createContentVersion(String name, Blob body) already accepts the content as a Blob, so VersionData must be directly set with body. EncodingUtil.base64Decode(body) comes into play if the input body was of type String. Jun 15 '20 at 21:37
  • Note that SOQL on this line: contentVersions = [SELECT Id, ContentDocumentId FROM ContentVersion WHERE Id IN :contentVersions]; is critical. See: salesforce.stackexchange.com/a/248914
    – Gillespie
    Aug 11 at 15:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.