I'm sending emails like this:

Messaging.SingleEmailMessage m = new Messaging.SingleEmailMessage();
m.setToAddresses( new String[]{'[email protected]'} );
m.setSubject(       'test' ); 
m.setHtmlBody(      '...' );
m.setWhatId(        anyObjectId );
Messaging.EmailFileAttachment efa = new Messaging.EmailFileAttachment();
efa.setBody( pdfBlob );
efa.setContentType('application/pdf'); // does not work: (cv.FileType);
m.setFileAttachments( new Messaging.EmailFileAttachment[]{ efa });
Messaging.sendEmail(new Messaging.SingleEmailMessage[] { m });

Now this perfectly work and the sent email shows up at the record with anyObjectId in the activity tab.

It even shows the paper-clip icon for the attachment. Only that the attachment itself is not visible:

enter image description here

It should look like this (created by sending an email OUT using the LEX UI):

enter image description here

I'm pretty sure that there is a ContentDocument, ContentVersion and a ContentDocumentLink (aka "Share") missing. Looking at the ContentDocument records of emails sent via the LEX-UI it should look like:

enter image description here

Now I would gladly manually add the missing ContentDocument, ContentVersion and a ContentDocumentLink, but only I can't because I can't get the Id of the EmailMessage as described in this question: How to get the Id of an EmailMessage after sending a SingleEmailMessage with Messaging.SendEmail()?

Any ideas on how to solve this?

  • Anyone ever find a good solution to this? I have the same problem. I can send the email via Apex with an attachment using setFileAttachments method, but can't get email Id to store attachment to the Email stored in Salesforce. Oct 10, 2020 at 19:45

4 Answers 4


The trick is to insert a ContentVersion first and then use the Messaging.SingleEmailMessage.setEntityAttachments method with the ContentVersion Id. The attachment goes out with the email and is stored in Salesforce. Sample below attaches a PDF. It is not bulkified, but you get the idea:

ContentVersion cv = new ContentVersion();
cv.VersionData = <yourBlobHere>;
cv.Title = 'myTitle';
cv.PathOnClient = 'myTitle.pdf';
cv.Description = 'myDescription';
cv.isMajorVersion = true;
insert cv;

Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
// Set your mail parameters...
mail.setEntityAttachments(new list<Id> {cv.Id});

List<Messaging.SingleEmailMessage> listEmails = new List<Messaging.SingleEmailMessage>(mail);
List<Messaging.SendEmailResult> listMailResults = Messaging.sendEmail(listEmails, false);
  • This works perfectly, you just need to create your ContentDocumentLinks etc after you've inserted the ContentVersion as normal if you want to relate the attachment files to more than just the EmailMessage e.g. if you want to directly relate them to more than just the 'WhatId'. I can post examples if needed. Jan 22, 2021 at 16:54
  • How do you retrieve the EmailMessage id once you have created?
    – Edmondo
    Feb 3, 2021 at 17:10
  • @Edmondo1984 - I don't retrieve the EmailMessage Id because I don't need it. I insert the attachment first as a ContentVersion, then use the ContentVersion Id to attach it to the EmailMessage and send the EmailMessage. I never need the EmailMessage Id. Feb 3, 2021 at 18:56

The only solution I could figure at all is to sadly forget about the incomplete EmailMessage Salesforce has been created for us and start over from scratch by inserting a brand new EmailMessage having proper attachments.

This is very sad, because

  • it's not even easy to delete the incomplete one with out a trigger and some kind of flagging it. So I just forget about it an let it rot.
  • currently letting it rot doesn't much because I removed the line m.setWhatId( anyObjectId ); so that the crippled record is not showing up on the parent record.
  • now my new EmailMessage has attachments, but lost the paper-clip indicating the attachments. Strangely the one without attachments Salesforce is creating has that paper-clip.

Im still looking for a better and cleaner solution on this.

@Salesforce is that overall behavior "as designed" and considered a feature - or a bug? I would love not to have to do all this on my end. It feels wrong.


You need to set m.setEntityAttachments(lstContentVersionIds); where lstContentVersionIds is the list of contentversionIds of the files attached.

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

Now you will be able to see the attachments as well.


You can get the email message Id on a trigger on EmailMessage. Then you can add manually the missing relationships.

  • it is not easy to do so, because in the trigger context, I missing the following infos: a) if this email has to be processed or not (one those create by the code above should be) b) the attachments are not available in the trigger context. I think a) could be solved but b) not.
    – Uwe Heim
    Jul 11, 2018 at 15:05
  • But the attachments should be queryable, no? Even if you need to wait for the email's trigger context to finish, you can get an async method to run on the created records. Seems an awful lot of work, but it is the only way I can think of solving this problem. Jul 11, 2018 at 15:24
  • 1
    I doubt that the attachments are stored at all. Expressis verbis I think neither the ContentDocument, nor the ContentDocumentVersion, nor the ContentDocumentLink will be created but ONLY the EmailMessage, just having the Boolean HasAttachments set to true. My approach now is to delete the EmailMessage created by Salesforce and constructing the whole quartet of entities (EM,CD,CS,CDL) and proper relations in my code. Way easier as working in a trigger context but still not nice... i think either should Salesforce do EVERYTHING or NOTHING - but not just half of the work.
    – Uwe Heim
    Jul 11, 2018 at 15:48
  • Are you suggesting that we have a trigger on the emailmessage that will create the ContentDocumentLink?
    – Edmondo
    Feb 3, 2021 at 19:48
  • I suggested the usage of a trigger on the EmailMessage entity so that you can get its Id and "manually add the missing ContentDocument, ContentVersion and a ContentDocumentLink", as the OP said. Feb 4, 2021 at 11:39

You must log in to answer this question.

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