How to send multiple emails with one click in Dynamics CRM 2011
OK, so you probably know that through the use of campaigns or workflows you can generate and send emails to multiple recipients using email templates or the like.
But if you want to edit the generated emails or at least sanity check them before sending you will need to create them as draft and then send them manually.
This is fine but if you end up with 100 generated emails you might want to check 3 or 4 and if they're OK send the lot. Sounds reasonable but on trying to do just that, I found that you are limited in the CRM to sending them one at a time.
After checking that I wasn't missing something by posting on the CRM forumn I had my suspicions confirmed by Andriy a33ik Butenko (check the blog, its good)
There is no built in functionality for sending a list of selected email activities. Andriy suggested either Javascript executed from a button on the ribbon, or a custom workflow. I prefered the custom workflow approach but due to the incompatibility with CRM Online I would need to use a workaround.
This is what I did and it works a treat...
Step 1.
Create a custom Entity called 'SendEmailRequest'
Give the Entity a field of type lookup, and set the target record type to email
Save and publish your new entity.
Step 2.
Create a new Workflow Process and call it BulkSendEmail
Add a step to Create record and set it to create a new 'SendEmailRequest' (That we created above)
Then click "Set Properties"
Use the form assistant to set the lookup on the SendEmailRequest so that it points to the email that the workflow has been run on.
Finally save and close.
Activate this workflow.
Step 3.
Open Visual Studio and create a new Class library project.
Create a new class and call it SendEmailRequest_Plugin
Add references to the microsoft.crm.sdk.proxy, microsoft.xrm.sdk, System.Runtime.Serialization and System.ServiceModel
Paste this code into your new SendEmailRequest_Plugin Class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using System.Xml;
using System.ServiceModel;
namespace SendEmailRequest_Plugin
{
public class SendEmailRequest_Plugin:IPlugin
{
public const string CrmOrgPrefix = "YourPrefixHere_"; //Default is new_
public void Execute(IServiceProvider serviceProvider)
{
//Extract the tracing service for use in debugging sandboxed plug-ins.
ITracingService tracingService =
(ITracingService)serviceProvider.GetService(typeof(ITracingService));
if (tracingService == null)
throw new InvalidPluginExecutionException("SendEmailRequest_Plugin: Failed to retrieve the tracing service.");
// Obtain the execution context from the service provider.
IPluginExecutionContext context = (IPluginExecutionContext)
serviceProvider.GetService(typeof(IPluginExecutionContext));
if (context.Depth < 3)
{
Entity messageImage = new Entity();
//Get the postImage
if (context.PostEntityImages.Contains(CrmOrgPrefix + "postImage_sendemailrequest") &&
context.PostEntityImages[CrmOrgPrefix + "postImage_sendemailrequest"] is Entity)
{
messageImage = (Entity)context.PostEntityImages[CrmOrgPrefix + "postImage_sendemailrequest"];
}
try
{
//Create an instance of the organization Service
IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
//Extract the Email ID from the postImage of the SendEmailRequest
Guid emailId = ((EntityReference)messageImage[CrmOrgPrefix + "email"]).Id;
//Check the Email ID is populated
if (emailId != null && emailId != Guid.Empty)
{
ParameterCollection parameterCollection = new ParameterCollection();
parameterCollection.Add(new KeyValuePair<string, object>("EmailId", emailId));
parameterCollection.Add(new KeyValuePair<string, object>("TrackingToken", string.Empty));
parameterCollection.Add(new KeyValuePair<string, object>("IssueSend", true));
//Create a send email request
OrganizationRequest emailRequest = new OrganizationRequest
{
RequestName = "SendEmail",
Parameters = parameterCollection
};
//Execute the request
OrganizationResponse response = service.Execute(emailRequest);
tracingService.Trace(string.Format("SendEmailRequest_Plugin: Email '{0}', Submitted for delivery", messageImage[CrmOrgPrefix + "name"]));
//Clean up the SendEmailRequest
service.Delete(CrmOrgPrefix + "sendemailrequest", new Guid(messageImage[CrmOrgPrefix + "sendemailrequestid"].ToString()));
tracingService.Trace(string.Format("SendEmailRequest_Plugin: SendEmailRequest '{0}' was deleted (Cleaned up)", messageImage[CrmOrgPrefix + "name"]));
}
else
{
tracingService.Trace("SendEmailRequest_Plugin: Error Locating Email To Send on Send Email Request");
}
}
catch (FaultException<OrganizationServiceFault> ex)
{
throw new InvalidPluginExecutionException("An error occurred in the SendEmailRequest_Plugin plug-in.", ex);
}
catch (Exception ex)
{
tracingService.Trace("SendEmailRequest_Plugin: {0}", ex.ToString());
throw;
}
}
}
}
}
Build your project and register your plugin using the Plugin registration tool that comes with the dynamics SDK.
Under the plugin assembly of the registered plugins tree
Create a "Create" Step which should look like this: (the red block covers my publisher prefix yours will be new_ by default)
Under that "Create" step register a new image that should look like this
You should now be able to select a collection of saved emails and run the "SendBulkEmail" workflow on them. This will in turn create a SendEmailRequest item which will trigger the plugin which will load the email from the request, submit the email for delivery and then delete (clean up) the request.
To make this functionality even sweeter you could action it from a button on the Ribbon. I'll update this post to include that functionality soon.




