Custom Workflow Activity for matching email addresses to customers

In an earlier blog (E-mail to Case/Lead Using CRM 4 Workflow ), I described a sample workflow that could be used to automatically create cases based on emails sent to a queue.

One of the questions that was frequently asked for the above blog was that the email activity’s regarding field set to blank. In this blog, I’ll show how this can be done using a custom CRM workflow activity.

Let’s summarize the problem we are trying to solve. Joe (joe@mycustomer.com) is a customer in your system and say you have an account that is capturing this. Joe sends an email to your support alias to report an issue. We would like the email activity that is created to be regarding Joe’s account.

I’m going to split my solution into 2 parts:

1) A custom workflow activity that takes an email address as input and returns a matching account as output

2) A workflow rule that uses the above custom activity. This workflow rule is triggered when an email is created and updates the email activity to have the regarding field set to the output returned by the custom workflow activity.

Custom Workflow Activity

Let’s walk thru’ the code for the custom workflow activity.

1) Define the class skeleton and the using statements for the various namespaces that we will need.

using System.Workflow.Activities;

using System.Workflow.ComponentModel;

using Microsoft.Crm.Sdk;

using Microsoft.Crm.SdkTypeProxy;

using Microsoft.Crm.Workflow;

using Microsoft.Crm.Sdk.Query;

namespace CrmCustomWFActivity

{

   [CrmWorkflowActivity(“Find Customer with specified email address”)]

   public class MatchSenderWithExistingCustomerActivity:  

   System.Workflow.Activities.SequenceActivity

   {

       // Activity code goes here.

   }

}

2) Now, add properties that represent the inputs and outputs. As discussed earlier, the input is an email address (of type string) and the output will be the matching account (of type Lookup).

   1: // Input property
   2: public static DependencyProperty senderProperty = DependencyProperty.Register("sender", typeof(string), typeof(MatchSenderWithExistingCustomerActivity));
   3:
   4:         [CrmInput("Sender")]
   5:         public string sender
   6:         {
   7:             get
   8:             {
   9:                 return (string)base.GetValue(senderProperty);
  10:             }
  11:             set
  12:             {
  13:                 base.SetValue(senderProperty, value);
  14:             }
  15:
  16:         }
  17:
  18: // Output property
  19: public static DependencyProperty accountIdProperty = DependencyProperty.Register("accountId", typeof(Lookup), typeof(MatchSenderWithExistingCustomerActivity));
  20:
  21:         [CrmOutput("AccountId")]
  22:         [CrmReferenceTarget("account")]
  23:         public Lookup accountId
  24:         {
  25:             get
  26:             {
  27:                 return (Lookup)base.GetValue(accountIdProperty);
  28:             }
  29:             set
  30:             {
  31:                 base.SetValue(accountIdProperty, value);
  32:             }
  33:
  34:         }

3) This custom workflow activity needs to be able to retrieve accounts whose email address matches the sender property value. To do this, it needs to be able to call into CRM SDK methods and can do this thru’ IcrmService interface that is provided to all crm custom workflow activities. The following is code for a helper method that uses CRM query functionality to return account that matches the email address.

   1: private Guid MatchSenderWithExistingAccount(ICrmService crmService, string fromAddress)
   2: {
   3:     // Retrieve accounts with this email address.
   4:     QueryByAttribute query = new QueryByAttribute();
   5:     query.EntityName = EntityName.account.ToString();
   6:     query.Attributes = new string[] { "emailaddress1" };
   7:     query.Values = new string[] { fromAddress };
   8:
   9:     RetrieveMultipleRequest retrieveMultipleRequest = new RetrieveMultipleRequest();
  10:     retrieveMultipleRequest.Query = query;
  11:     retrieveMultipleRequest.ReturnDynamicEntities = true;
  12:
  13:     RetrieveMultipleResponse retrieveMultipleResponse = (RetrieveMultipleResponse)crmService.Execute(retrieveMultipleRequest);
  14:
  15:
  16:
  17:     Guid accountId = Guid.Empty;
  18:
  19:     foreach (BusinessEntity busEntity in retrieveMultipleResponse.BusinessEntityCollection.BusinessEntities)
  20:     {
  21:         // Pick the first accountid.
  22:         accountId = ((Key)(((DynamicEntity)busEntity)["accountid"])).Value;
  23:         break;
  24:     }
  25:
  26:     return accountId;
  27: }

4) Now, we can implement the Execute method of the custom workflow activity.

   1: protected override System.Workflow.ComponentModel.ActivityExecutionStatus Execute(System.Workflow.ComponentModel.ActivityExecutionContext executionContext)
   2:         {
   3:             IContextService contextService = (IContextService)executionContext.GetService(typeof(IContextService));
   4:             IWorkflowContext context = contextService.Context;
   5:
   6:         // Obtain IcrmService so we can call into CRM SDK to retrieve
   7:         // accounts
   8:             ICrmService crmService = context.CreateCrmService();
   9:
  10:             // this.sender property will have the email address that needs to be matched.
  11:             Guid accountId = MatchSenderWithExistingAccount(crmService, this.sender);
  12:
  13:             // Set the accountId output property to return this data
  14:         // back to the calling workflow
  15:             this.accountId = new Lookup("account", accountId);
  16:
  17:             return ActivityExecutionStatus.Closed;
  18:         }
  19:
  20:     return accountId;

Using The Custom Workflow Activity

In order to use MatchSenderWithExistingCustomerActivity in workflow rules, you need to register the activity.

We will create a workflow rule that does the following:

1) When an email is created, it checks if the email’s regarding field is set.

2) If not set, it invokes MatchSenderWithExistingCustomerActivity

3) It updates email with the accountid returned by MatchSenderWithExistingCustomerActivity.

Let’s walk through these in more detail.

1) Create the workflow rule, call it SetEmailRegarding and set it to trigger on email create

clip_image002

2) Insert a check condition step and configure it to check if Email:regarding field does not contain data

clip_image004

3) If Email:regarding is not set, we want to invoke the MatchSenderWithExistingCustomerActivity. Under the add step drop-down, you should find the custom workflow activity as shown below:

clip_image006

4) After you select MatchSenderWithExistingCustomerActivity, you need to ensure that it is being invoked with the correct input. Click ‘Set Properties’ and set the value of the input parameter Sender to that of Email:Sender

clip_image008

5) The next step would be to update the email’s regarding to the value returned by the custom workflow activity in the previous step. To do this, add a Update Email step, select ‘Set Properties’ and tab to the ‘Regarding’ field. In the dynamic values form assistant, you will now find that it shows ‘Match email address:accountid’ to indicate the return value from the previous step. Select this to be the value for regarding field as shown below.

clip_image010

6) Publish the workflow and verify that it is working.

Since the functionality to match email address to an account has been captured as a custom workflow activity, you will be able to use that activity in all your workflow rules. You can also enhance the custom workflow activity by making it return either a matching account or contact if needed. If you need to create an account/contact if a match wasn’t found, you can do this by adding a Create step to the workflow rule.