Extending [Logical Users] list in Workflow


Hi guys,


Here is an example about how to call an assembly from the WF manager. This example deals with a request we had from a customer about how to extended the sendmail functionnality in order not to be limited by the [Logical User] list offered out of the box.

I have to thank Clint Warriner for his help about the logical implemention 🙂


Here we go:


When you want to send an email via the Workflow manager inside your rule, you have the choice to select a particular recipient for your mails, or to choose the "Logical User" list, this list depends of the type of record you refer to.


Here is the list of "Logical User" listed for a case.


 SendMail Action in Workflow Manager


 Here is the signification of the abover "Logical User" list:


[account/contact] Sends email to the account or contact associated with the case
[account] Sends email to the associated account for this case (customer field)
[contact] Sends email to the associated contact for this case (customer field)
[owner's manager] Sends email to the associated owner's manager of this case record.
[owner] Sends email to the associated Owner of the case record.


Here is bellow to which field these Logical Users refer to (in the Case Record):


Case Record


 The problem is:


What if I want to to something esle? Like:


=> Send the email to the Logical Account (customer in the TO: Line of my Email) and its Primary Contact in CC: Line ?


This is not possible in the regular workflow interface, so you need to develop you own SendMail Workflow Assembly and call it into workflow manager.

The code will:


- retrieve the customer properties (account), search for it's "PrimaryContact" property
- based on this, an EMail activity will be created with the Account (customer) in the TO Line and its primary contact in the CC Line
- then we send the email.


[note: we check the customer is an account (OTC =1) before trying to fill the CC line, we don't handle the situation where the Customer is a contact]


It's provided as is, there is no error handling at all, you will need to add the CrmSdkHelpers.Cs file provided by the CRM 3.0 SDK to do this:


using System;
using CrmSdk;
using SendMailToPrimaryContact.crmsdk;


namespace SendMailToPrimaryContact


{


/// <summary>
/// Summary description for Class1.
/// </summary>


public class MailToCustomer


{


public void CreateMailAndSendIt(Guid guidOfCustomer, int ObjectTypeCode)


{


// create CrmService instance


CrmService csvc = InitWebSvc();


// Create New EMAIL


email e = new email();
e.ownerid =
new Owner();
e.ownerid.type = EntityName.systemuser.ToString();
e.ownerid.Value =
new Guid("302A6CD7-8E63-DA11-BC4B-0003FF0D54C9"); // to simplify things, we set static owner to admin...
e.subject = "A new case has been created (mail sent by custom DLL)"; // Email Subject
e.description = "Hi All, here is a new mail to notify you that a new case has been created"; // Email Body


// create an ActivityParty matching the customer guid to fill the TO line with....
activityparty ap = new activityparty();
ap.partyid = CrmSdk.CrmTypes.CreateLookup(EntityName.account.ToString(),guidOfCustomer);


// fill the TO Field with the customer....
e.to = new activityparty[]{ap};


// fill the CC Field with the primary contact of this customer....
if(ObjectTypeCode==1)
{
e.cc =
new activityparty[]{RetrievePrimaryContact(guidOfCustomer)};
}


// Actually create the mail activity.
Guid emailid = csvc.Create(e);


// Send the mail.
SendMyMail(emailid);


// release resource.
csvc.Dispose();


}


public CrmService InitWebSvc()


{


CrmService csvc = new CrmService();
csvc.Credentials = System.Net.CredentialCache.DefaultCredentials;
csvc.PreAuthenticate =
true;
csvc.UnsafeAuthenticatedConnectionSharing =
true;
return csvc;


}


public void SendMyMail(Guid emailid)


{


// create CrmService instance
CrmService csvc = InitWebSvc();
// Send the Email based on the EmailId provided.
SendEmailRequest req = new SendEmailRequest();
req.EmailId = emailid;
req.TrackingToken =
string.Empty;
req.IssueSend =
true;
SendEmailResponse res = (SendEmailResponse)csvc.Execute(req);
// release ressource.
csvc.Dispose();


}


public activityparty RetrievePrimaryContact(Guid accountid)


{


// create CrmService instance
CrmService csvc = InitWebSvc();


// Creating ActivityParty matching the PrimaryContact
ColumnSet cs = new ColumnSet();
cs.Attributes = new string[]{"primarycontactid"};
activityparty ap =
new activityparty();
Guid primarycontactGUID = ((account)csvc.Retrieve(EntityName.account.ToString(),accountid,cs)).primarycontactid.Value;
ap.partyid = CrmSdk.CrmTypes.CreateLookup(EntityName.contact.ToString(),primarycontactGUID);


// release ressource.
csvc.Dispose();


return ap;


}


}


}


Compile the code in Visual Studio 2003.


Now you have an Assembly DLL called: SendMailToPrimaryContact.dll
The name of your Class is: MailToCustomer()
The main method is: CreateMailAndSendIt()


Now you need to update your Workflow.Config file to handle your freshly created DLL:


Go to C:\Program Files\Microsoft CRM\Server\bin\assembly\ and Edit the Workflow.Config file

If the assembly is unsigned, you must add the allowunsignedassemblies attribute to the <workflow.config> element at the top of the Workflow.config file. Assign a value of "true" to the allowunsignedassemblies attribute. To update the Workflow.config file, use the following code sample.


<method name="Send Mail to Customer When Case Created"
              assembly="SendMailToPrimaryContact.dll"
             
typename="SendMailToPrimaryContact.MailToCustomer"
             
methodname="CreateMailAndSendIt"
             
group="Send Mail"
              description="benlec">
             <
parameter name="Customer" datatype="lookup" entityname="account"/>
             <
parameter name="CustomerOTC" datatype="integer" default="0"/>
             <
result datatype="boolean"/>
</
method>


Copy now SendMailToPrimaryContact.Dll into this directory too.


 


Now that you're done with the Config file and your DLL, create a MANUAL workflow rule which will call this assembly when a CASE is created.


 


Call Assembly


 


Now you will need to setup the rule by specifying the 2 parameters we defined in the workflow config.


 


Here is what you have:


 


Rule Configuration 1


 


Double click on each parameter, select CustomerOTC static Value = 1, and Customer dynamic value = Account.


You should have something like this:


 


Rule Configuration 2


 


Click Save and Activate your rule.


 


Now when you create a case, and fill the customer field with your Account have a primary contact, click "More Actions" menu and apply the rule we created.


 


The Email created and sent shall look like this:


 


EMail Received


 


Hope this helps, here are some usefull things around this topic:


 


922607 How to use the Logical User fields in Microsoft Dynamics CRM 3.0 workflow rules
http://support.microsoft.com/default.aspx?scid=kb;EN-US;922607


 


Sending email via workflow as different user


http://blogs.msdn.com/crm/archive/2006/11/15/sending-email-via-workflow-as-different-user.aspx


 


Kind regards


 


Benjamin LECOQ

Comments (10)
  1. Hi Guys, More than only dealing with the Support Tools, I’ve just added a CRM SDK section to this blog

  2. PhilBriz says:

    Mmhhh, sweet, I’m loving it.

    Pretty cool way to demonstrate Workflow assembly 101.

    Great Post !

  3. albanosa says:

    Hi, I tried you code but i reseave an error regarding the CrmBoolean type.

    I add the CrmSdkHelpers.Cs file, but can’t compile.

    Thanks

  4. JGC says:

    Hi, I’m having some problems to implement this solution.

    When I call the line Guid emailid = csvc.Create(e); I receive the messagem "Server was unable to process request".

    I receive the error on this line because i passed to procedure 0 at secound parameter, just to teste.

    Thanks

  5. MSDN Archive says:

    Hi Guys,

    Can you try to be precise with the Errors and exceptions you have?

    The code provided here does not handle any error, you need to modify it to dump the appropriate errors.

    Implement Try/Catch like this:

    try

    {

      Guid emailid = csvc.Create(e);

    }

    catch(System.Web.Services.Protocols.SoapException ex)

    {

      Console.WriteLine(ex.Message + "." + ex.Detail.InnerText);

    }

    Regards

    Benjamin

  6. JGC says:

    Hello,

    The error is "Server was unable to process request..n0x80040217nThe specified object was not found.nPlatformn" could be something with the web services.

    I created a project and made a Web reference to the web-Services, the link is ok I already confirm, but when I invoke this method of a WS receive this error.

    The MSCRM is installed in other machine there is any problem with this? I read something about Remote connections or something like this…

    Thanks,

    JGC

  7. Ana Martinho says:

    Hi Benjamin,

    Thanks for your help.

    the error is "Server was unable to process request..n0x80040217nThe specified object was not found.nPlatformn"

    Thanks

    Ana

  8. Jason says:

    When I try to run the rule on a case I get this error in the event viewer

    Action {57EDFAE5-E567-DC11-920E-00010321C609} failed in step {55EDFAE5-E567-DC11-920E-00010321C609} of process instance {3C4E0294-E767-DC11-920E-00010321C609}. Please view the paused rule in the Microsoft.Crm.Workflow.Monitor for more information about the failure.

    When I look in the workflow monitor I see this error

    Error code =80070005 Access Denied. You do not have suffient access rights or priviliges to perform this action.

    I am logged in as administrator and restricted access is off for the admin user.

    Any help would be great.

    Thanks

  9. MSDN Archive says:

    Try to run the Workflow Service under LocalSystem account….

  10. Lorena says:

    Hi, if I need to add the field CREATEDBY in the logical user list at workflow, I need to do this same dll?

Comments are closed.

Skip to main content