How to Move Attachments from an Email to a Case in Dynamics CRM 2011

Microsoft Dynamics CRM 2011 provides users with the ability to convert an e-mail to a Case, but when the Case is created, any attachments on the e-mail remain on the e-mail.  In order for users to view those attachments when they are looking at the Case, they must find the original e-mail.  All these clicks can get quite cumbersome for already maxed out users!

One of the ways to address the problem would be to copy the attachments to the Case. The benefit is that the attachments would be on the Case and therefore easy to get to (and would also remain on the original e-mail for historical purposes). The only problem with this is that we now have duplicate attachments, potentially causing unnecessary database bloat.

Another solution (the one I’ll walk you through here), is to move the attachments to the Case.  The following tutorial will show you how to move attachments from an e-mail to a Case via a custom workflow activity.

Step 1: Create the Custom Workflow Activity
The first step when creating the code is to create a project, add the Microsoft.Xrm.Sdk.dll and Microsoft.Xrm.Sdk.Workflow.dll references. (Both of these files can be found in the SDK. Click here to download.)

Next, we setup the framework for workflow activity by adding the correct using statements, namespace and creating a public sealed class that inherits from CodeActivity.  Within the class, we will add the required input parameters for the E-mail and the Case that we will be working with.

usingMicrosoft.Xrm.Sdk.Workflow;namespaceMoveAttachmentsToCase{    public sealed class MoveAttachmentsToCase : CodeActivity


public InArgument<EntityReference> EmailReference { get; set; }

public InArgument<EntityReference> CaseReference { get; set; }    }  }

Next, we need to add the Execute method to the class. This method will get the service object and then the input parameters and then pass them to the worker function called ReparentAttachments.

protectedoverride void Execute(CodeActivityContext executionContext){    //Create the service object
IWorkflowContext context = executionContext.GetExtension<IWorkflowContext>();
IOrganizationServiceFactory serviceFactory = executionContext.GetExtension<IOrganizationServiceFactory>();
IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);// Get the e-mail reference object
EntityReference emailRef = EmailReference.Get<EntityReference>(executionContext);// Get the case reference object
EntityReference caseRef = CaseReference.Get<EntityReference>(executionContext);

// Create an Entity Reference for the case
Entity caseEntity = new Entity(“incident”);

caseEntity.Id = caseRef.Id;
// Move the attachments

ReparentAttachments(service, emailRef.Id, caseEntity); }

The Reparent Attachments function goes and gets all the attachments from the e-mail and loops through each of them to get the actual file, create a new note, then delete the original attachment.  This is more of a copy than a move, since the structure for attachments is different on e-mail records than it is on Cases. You will also notice that there is a call to GetAttachment that seems a bit redundant, but it is not. While stepping through the code, I found that I needed to go one more level in to be able to get ahold of the actual file.

publicvoid ReparentAttachments(IOrganizationService service, Guid emailId, Entity caseEntity){    // Query the system for all the attachments
RetrieveMultipleRequest getRequest = new RetrieveMultipleRequest();
QueryExpression qex = new QueryExpression(“activitymimeattachment”);qex.Criteria = new FilterExpression();
qex.Criteria.FilterOperator = LogicalOperator.And;
qex.Criteria.AddCondition(new ConditionExpression(“objectid”, ConditionOperator.Equal, emailId));qex.ColumnSet.AddColumn(“activitymimeattachmentid”);
getRequest.Query = qex;

RetrieveMultipleResponse returnValues = (RetrieveMultipleResponse)service.Execute(getRequest);
// Loop through each attachment
foreach (Entity att in returnValues.EntityCollection.Entities)

{ EntityReference attachmentRef = (EntityReference)att[“attachmentid”];
// Now go get the actual attachment record
Entity attachment = GetAttachment(service, attachmentRef.Id);

if (attachment == null) { break; }
// If the attachment has the all the important parts, create a new note
if (attachment.Attributes.Contains(“body”) &&
attachment.Attributes.Contains(“filename”) &&

{Entity note = new Entity(“annotation”);
note.Attributes.Add(“objectid”, caseEntity.ToEntityReference());
note.Attributes.Add(“objecttypecode”, 112);
note.Attributes.Add(“subject”, “Attachment Moved from E-mail”);
note.Attributes.Add(“documentbody”, attachment.Attributes[“body”]);
note.Attributes.Add(“filename”, attachment.Attributes[“filename”]);
note.Attributes.Add(“mimetype”, attachment.Attributes[“mimetype”]);

// Create the new note
// Delete the old attachment
service.Delete(“activitymimeattachment”, att.Id);        }  } }

Now, add the GetAttachment function, and then you are ready to build!

privateEntity GetAttachment(IOrganizationService service, Guid attachmentId){ RetrieveMultipleRequest getRequest = new RetrieveMultipleRequest();
QueryExpression query = new QueryExpression(“activitymimeattachment”);
query.Criteria = new FilterExpression();query.Criteria.FilterOperator = LogicalOperator.And;
query.Criteria.AddCondition(new ConditionExpression(“attachmentid”, ConditionOperator.Equal, attachmentId));
query.ColumnSet.AddColumn(“body”);getRequest.Query = query;
RetrieveMultipleResponse returnAttachments = (RetrieveMultipleResponse)service.Execute(getRequest);

if (returnAttachments.EntityCollection.Entities.Count > 0)
{ return returnAttachments.EntityCollection.Entities[0];   }
{  return null;   }}

Step 2: Register the Custom Workflow Activity
Now that the code is written, the plug-in needs to be registered.

1.) Open the plugin registration tool and connect to your organization.

2.) Click on the Register button and then Register New Assembly.

3.) Select the DLL that was created when the project was built.  If you want to accept all the defaults, then click OK.

4.) Click OK on the notice that the plug-in was registered successfully.

5.) Change the Name and WorkflowActivityGroupName to something friendly.

6.) Click the Save button.
Step 3: Create the Workflow Process
When an e-mail is converted to a Case, the Regarding field is set to the resulting Case. This is true even if the e-mail is completed and therefore read-only.  So we will create a workflow rule that fires when the e-mail’s regarding object is changed.  Follow the steps below to create this workflow.

1.) Create a new process with the following values (name it whatever makes sense to you):

a.)  Entity = E-mail
b.)  Category = Workflow

2.) In the Options for Automatic Processes section:

a.) Uncheck Record is created
b.) Check Record fields change
c.) Click on the Select button
d.) Select Regarding

e.) Click OK.

3.) Add a Check Condition.

4.) Click on the condition link to set the condition.

5.) Set the condition to check that Regarding (Case) has a value.  This means that the Regarding field is a Case.

6.) Select the row within the check condition.

7.) Click Add Step -> Custom Activities -> Move Attachments From E-mail To Case.

8.) Click on the Set Properties button.

9.) Set the E-mail to the E-mail Message and the Case to the Regarding field.

10.) Click Save and Close.
11.) Add labels to the steps.

12.) In the ribbon, click the Save button.

13.) In the ribbon, click the Activate button.

Now that the plug-in is written, registered, and we have a workflow activated on update of the regarding field on E-mail, whenever we use the Convert to Case functionality, the attachments will get moved.

For more information on this customization, submit your questions below, or contact us today

Phone: 312-602-4000
222 W. Adams
Chicago, IL 60606
Show Buttons
Share On Facebook
Share On Twitter
Share on LinkedIn
Hide Buttons