Sunday, March 15, 2009

Techniques for Driving MS CRM Email Templates

The email templates in MS CRM can be leveraged as a powerful building block when generating emails programmatically.

Tips:

  • Generate your HTML in another editor and then paste it into the template editor to add data slugs.
  • Associate your template with the entity that you want the most information from.
  • Use Template Naming conventions that organize things and make programmatic template selection easier.

For an example lets say that we have product specific Quote Letters.

Using my helper method from a previous blog article, grab an email template matching a specific name based on the product.

// Get appropriate Template
BusinessEntityCollection templates = 
   h.GetAllEntitieswithFilter(EntityName.template.ToString(), new[] { "templateid" }, new[]{"title"}, new[]{emailTemplateTitle});

Then create a new InstantiateTemplateRequest using the template id and point it at an entity with the information that you want merged in. This must be the same type that you associated your template with when you created it.

var instTemplate = new InstantiateTemplateRequest
     {
         TemplateId = thisTemplate.templateid.Value,
         ObjectId = quoteId,
         ObjectType = EntityName.quote.ToString()
     };


// Execute the request to create an email message from the template.
var instTemplateResponse = (InstantiateTemplateResponse)h.service.Execute(instTemplate);

var newEmail = (email)instTemplateResponse.BusinessEntityCollection.BusinessEntities[0];

The result of the InstantiateTemplateResponse is an email entity collection. For this example we just have one email.

From here you can regard the email to a completely different entity if you want. It is only important that the ObjectId and ObjectType be set for the merge process. After that is complete this is just another email with a bunch of fields pre-filled. Now you can have your way with it like any other email that you created from scratch. This is critical to making the best use of email templates.

Additional Merging
If you are calculating other numbers or pulling information from another data source outside of CRM, there is no reason to limit merging to what can be represented as data slugs.

In this example I am using putting additional information into the email body with a simple string replace using an agreed upon naming convention to represent additional merge fields.

// If template had #EmbedLicense# in body replace it with the license information
newEmail.description = newEmail.description.Replace("#EmbedLicense#", embedFile);

From here you can add attachments as shown here.

Proofing before Email is Sent
Another useful thing to do if you are doing this in a web application or a client Winform application is save the email and then open it in a new window for final review before it is sent. To do that generate a URL like the following with your orgname and email id passed in. You can get the CRM server base URL from the registry as shown here which you need for your web service reference, and then use the following: CrmServerBaseUrl = CrmServiceUrl.Substring(0, CrmServiceUrl.ToLower().IndexOf("mscrmservices"));

 // Open newly created email activity at this Url.
var emailUrl = h.CrmServerBaseUrl + "/"+orgname+"/activities/email/edit.aspx?id={" + emailId + "}";

From a WinForm application you can pop a CRM screen up like this.

For a web application register some JavaScript in the code behind that sets the value of the new email's URL.

 // Sets Javascript variables to envoke Window Open to new Explorer Window with body onload event
const string SETQUERYSTRING_SCRIPT = "Email_String";

if (!Page.ClientScript.IsClientScriptBlockRegistered(SETQUERYSTRING_SCRIPT))
{
   Page.ClientScript.RegisterClientScriptBlock(GetType(), SETQUERYSTRING_SCRIPT, string.Format(@"<script language=""javascript"">emailRecordUrl = '{0}';</script>", emailUrl));
}

Then in the aspx file use the following JavaScript code to open the new window. Call the script from the onload of the body.

<script type="text/javascript"> var emailRecordUrl = ""; function UpdateCRMFormGenerateEmail() { if (emailRecordUrl != "") { window.open( emailRecordUrl,
"_blank", "toolbar=no,scrollbars=yes,resizable=yes"); emailRecordUrl = ""; } } </script> </head> <body onload="UpdateCRMFormGenerateEmail();">

3 comments:

Giacomo Bertini said...

Hi Mark,
great post! I'd like to know if according to you there are a size limit in composing email body (field description). It seems we have a send problem if size is greater than about 4kbyte.

We use workflow service in MS Crm 3.0

Thank you in advance.

CS said...

Hello Mark,

Always good work from you.
I had to come back to emails and re-discovered that templates were no availables when distributing 'email channel' activities in campaigns.
Do you think it is possible to replace DistributeCampaignActivityRequest when a global loop on compatible list members ?

Are you still on Crm ?
Best regards
CS

Mark Kovalcson said...

CS,

Yes, I'm still on CRM, but have been distracted by xRM product development for a while.

Interesting question. Are you looking to intercept one event with a Plug-in and fire a different event? Or are you talking about overridding the stock request supplied by the SDK?