Dynamics CRM 2015 – Adding All Opportunity Notes Attachments to Workflow Emails

We had a need to send custom workflow emails that included all attachments from the Notes section of Opportunities in Dynamics CRM 2015. This is not an out of the box functionality. It requires the development of a plugin that must be registered in CRM to achieve the desired results. I’ll try to be thorough in my explanation, because I know it can be tough to put together the bits of information that you will find on this topic if you’re just starting out developing for CRM. 

It is important that I note here that I obtained most of the information needed to create this from this article. It was written for doing similar functionality for a single attachment in the Accounts entity, but I needed a way to get every attachment from the Opportunity entity. One of the commenters posted what they had done unsuccessfully in the comments section and I merely combined the code from the two people and made a working Opportunity plugin that includes all attachments – instead of only the first one. You’ll notice that I didn’t even bother fixing the spelling error on “attachement”. Feel free to do so in your own project.

  • You’ll need the Dynamics CRM 2015 Software Development Kit. You can download it here. Without this, you won’t have the required DLLs for adding as references to your project in Visual Studio and you won’t have the plugin registration tool (SDK folder\SDK\Tools\PluginRegistration).
  • You will also need Visual Studio, obviously.
  • You may also need to install .NET Framework 4.5.2, if you haven’t already.
    1. Create a new project in Visual Studio. The settings should look like the following:


    1. Rename the class file to SendEmailWithAttachement.cs to match the file.
    2. Right click on your project name (EmailAttachment), below your solution name in the Solution Explorer, click Properties. Click on the Signing tab. Check the box to Sign the assembly. If you don’t do this, you’ll get errors when you try to register your plugin with CRM. You don’t need a password, so make sure you clear that box. It should look like below:


    1. You’ll need to right click on References in the Solution Explorer and Add Reference a few times. Some will be part of Assemblies Framework and other you need to browse and obtain from the SDK. Be sure you have similar to the following screenshot when you are done:


    1. Now you’ll want to click on the SendEmailWithAttachement.cs class file to open it. Paste the following code in to it:

using System;
using System.Linq;
using System.Activities;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Workflow;
using Microsoft.Xrm.Sdk.Query;
using Microsoft.Crm.Sdk.Messages;

namespace EmailAttachment
public class SendEmailWithAttachement : CodeActivity

//define output variable
public InArgument SourceEmail { get; set; }

protected override void Execute(CodeActivityContext executionContext)
// Get workflow context
IWorkflowContext context = executionContext.GetExtension();
//Create service factory
IOrganizationServiceFactory serviceFactory = executionContext.GetExtension();
// Create Organization service
IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
// Get the target entity from the context
Entity OpportunitiesID = (Entity)service.Retrieve(“opportunity”, context.PrimaryEntityId, new ColumnSet(new string[] { “opportunityid” }));

AddAttachmentToEmailRecord(service, OpportunitiesID.Id, SourceEmail.Get(executionContext));

private void AddAttachmentToEmailRecord(IOrganizationService service, Guid OpportunitiesID, EntityReference SourceEmailID)
//create email object
Entity _ResultEntity = service.Retrieve(“email”, SourceEmailID.Id, new ColumnSet(true));
QueryExpression _QueryNotes = new QueryExpression(“annotation”);
_QueryNotes.ColumnSet = new ColumnSet(new string[] { “subject”, “mimetype”,”filename”,”documentbody” });
_QueryNotes.Criteria = new FilterExpression();
_QueryNotes.Criteria.FilterOperator = LogicalOperator.And;
_QueryNotes.Criteria.AddCondition(new ConditionExpression(“objectid”, ConditionOperator.Equal, OpportunitiesID));

EntityCollection _MimeCollection = service.RetrieveMultiple(_QueryNotes);

if (_MimeCollection.Entities.Count > 0)
for (int i = 0; i < _MimeCollection.Entities.Count; i++) { //we need to fetch first attachment Entity _NotesAttachment = _MimeCollection.Entities[i]; //Create email attachment Entity _EmailAttachment = new Entity(“activitymimeattachment”); if (_NotesAttachment.Contains(“subject”)) _EmailAttachment[“subject”] = _NotesAttachment.GetAttributeValue(“subject”);
_EmailAttachment[“objectid”] = new EntityReference(“email”, _ResultEntity.Id);
_EmailAttachment[“objecttypecode”] = “email”;
if (_NotesAttachment.Contains(“filename”))
_EmailAttachment[“filename”] = _NotesAttachment.GetAttributeValue(“filename”);
if (_NotesAttachment.Contains(“documentbody”))
_EmailAttachment[“body”] = _NotesAttachment.GetAttributeValue(“documentbody”);
if (_NotesAttachment.Contains(“mimetype”))
_EmailAttachment[“mimetype”] = _NotesAttachment.GetAttributeValue(“mimetype”);

SendEmailRequest SendEmail = new SendEmailRequest();
SendEmail.EmailId = _ResultEntity.Id;
SendEmail.TrackingToken = “”;
SendEmail.IssueSend = true;
SendEmailResponse res = (SendEmailResponse)service.Execute(SendEmail);



At this point, if you have any underlines or errors showing in the code, you are likely missing a reference.

    1. Build your plugin at this point by clicking on Build – Build Solution. If it builds correctly and you have no errors, you should be ready to register your plugin in CRM.
    2. Inside of the SDK folder that you unzipped, open SDK\Tools\PluginRegistration. Run the PluginRegistration.exe file to open the tool.
    3. Click on the Create New Connection button. If you’ve never run the registration tool, you’ll need to enter your local settings. Select On-premises. Enter the Server name. If you use SSL, make the port 443 and check the box to Use SSL. You’ll probably want Authentication Source to be Active Directory and then enter your user and Domain information. Click on the Login button. If all is correct, the system should login and provide you with the registration tools.
    4. Click on the Register button then on Register New Assembly.
    5. In the Register New Assembly window, use the browse button to locate and select your newly built DLL file. It should look like the following:


    1. Click on the Register Selected Plugins button. If all goes well, you’ll now see the new plugin in the list of Registered Plugins & Custom Workflow Activities. You can close out of the registration tool at this point.

All that is left is to open CRM and build your new workflow.

    1. Go to Settings – Processes. Click the New button to start a new workflow. Give it a name, set Category to Workflow and select Opportunity for the Entity. Be sure that New blank process is selected and click the OK button. It should look similar to below:


    1. At this point, just create a condition that is needed by your workflow. Add steps to process when meeting those conditions. I’ll skip over this as everyone’s will differ, but I will point out that to make this work, you want to Add Step, select Create Record and then select Email for the Create dropdown list.
    2. Click on the Set Properties button and enter the information in to your email form that you wish to send.
    3. Click on Add Step and select CRM_NoteAttachments ( and then EmailAttachment.SendEmailWithAttachement or whatever your name was for your plugin. Mine is shown below:


    1. Click on Set Properties and configure like the following:


    1. Click on Save and Close and then you’ll have your basic workflow, ready for activation and testing. Here is the final view of a test workflow:


Hopefully, this will fill enough gaps in the process for you to figure out the process for this. It took a lot of reading for me to get this working properly, using multiple forum threads. I just wanted to lay it out from beginning to end so that it saves someone else some time. Please check out the thread that I got most of the code from as well. That person deserves a lot of credit for his work.

Leave a Reply

Your email address will not be published. Required fields are marked *