Pages

Sunday, November 11, 2012

SharePoint : Custom Email for Task with Outlook ribbon control “Open this Task”

I came across a very interesting requirement with respect to “Tasks” in SharePoint but before we get into the requirement lets get into few details first.

As most us are aware of the fact that when a task item is created, either directly in the task list or through a Workflow an alert email would be sent saying a task has been assigned to you (provided alerts are enabled). When we look at that email in Outlook we see an additional control in the ribbon “Open this Task” under the group “Open” as shown in the figure


Now let me explain the requirement: We have a custom workflow built using sequential workflow template in Visual studio 2010. The customer is not convinced with the details in the email body generated by SharePoint.

  1. we have to customize the body and subject as per their request
  2. Retain that Ribbon control “Open this Task” when the email is sent
  3. If possible, have the “From Address” in the email to be the person who initiated this workflow
That is all what was requested, looks very reasonable, simple and straight forward. When I started implementing it my first impression was it is not as simple as it looks. Later on when I went through different approaches I felt I wasn’t very wrong about this requirement and eventually it turned out be a very simple solution. As they often say “All things are difficult before they are easy”. So I thought I would post my approaches and the final solution.

  • I have used “SPWorkflowTaskProperties” class in the Task Created Event and sent it two properties “SPWorkflowTaskProperties.HasCustomEmailBody = true” and “SPWorkflowTaskProperties.EmailBody= ” With this I can satisfy requirement 1 & 2 but not 3 (listed above).  Also if I were to create a task and if I want to send an email using Event Handler on item created I may not be able to use this. So for the generic purposes this would not fit in.
  • Next I thought of modifying the alert template but then it would have an impact on all task lists which is not a recommended option.
  • So, I have decided that I have to disable the alerts for that Task list and “SmtpClient or SPUtility” class to send email which can be used at different requirements such as “event handlers/workflows or any other for that matter. With this class we do have control over all the aspects “From, To, Subject, Email Body, etc”. The only problem with this to achieve the requirement # 2 (Ribbon control in outlook). I always wondered how would outlook recognize that an email is for Task, how is this ribbon control activated as soon as it sees an email.

I believed that the alert email sent has some headers which mark this as Task which is understood by outlook and displays the controls accordingly. So now the question is what are those headers. After some research I figured out the Mail message headers. Below is the code for sending an email which also includes those headers and satisfies all the above mentioned requirements (1, 2 & 3)

///
      /// Send Email with a control “Open this Task” in Outlook ribbon
      ///

      /// SharePoint Web Object (SPWeb)
      /// Body of the Email (string)
      /// Email Id of the recipient (string)
      /// SharePoint List item Object (SPListItem)
      /// Subject of the Email (string)
      ///
public object[] SendMail(SPWeb web, string HtmlBody, string ToEmailId, SPListItem listItem, string EmailSubject)
{
try
{ SPWebApplication webApp = web.Site.WebApplication;
MailMessage message = new MailMessage();
//Have a dynamic email address if you wish to change the From Address        message.From = new MailAddress(webApp.OutboundMailSenderAddress, web.Title);
message.BodyEncoding = Encoding.UTF8;
message.IsBodyHtml = true;
message.Body = HtmlBody;
message.To.Add(ToEmailId);
message.SubjectEncoding = Encoding.UTF8;
message.Subject = EmailSubject;
string domain = webApp.OutboundMailSenderAddress.Remove(0, webApp.OutboundMailSenderAddress.LastIndexOf(‘@‘));
message.Headers.Add("Message-Id", "<3BD50098E401463AA228377848493927" +Guid.NewGuid().ToString(“D“) + domain + “>“);
message.Headers.Add(“X-Sharing-Title“, this.ConvertToBase64String(listItem["Body"].ToString()));
message.Headers.Add(“X-AlertTitle“, this.ConvertToBase64String("System"));
message.Headers.Add(“Content-Class“, "MSWorkflowTask");
message.Headers.Add(“X-AlertWebUrl“, this.ConvertToBase64String(web.Url));
message.Headers.Add(“X-AlertServerType“, “STS“);
message.Headers.Add(“X-AlertWebSoap“, this.ConvertToBase64String(web.Url + “/_vti_bin/alerts.asmx“));
message.Headers.Add(“X-Sharing-Config-Url“, “stssync://sts/?ver=1.1&type=tasks&cmd=add-folder&base-url=” + Uri.EscapeDataString(web.Url) + “&list-url=” + Uri.EscapeDataString(listItem.ParentList.RootFolder.ServerRelativeUrl) + “&guid=” + Uri.EscapeDataString(listItem.ParentList.ID.ToString(“D“)));
message.Headers.Add(“X-Sharing-Remote-Uid“, listItem.ParentList.ID.ToString(“D“));
message.Headers.Add(“X-Sharing-WssBaseUrl“, this.ConvertToBase64String(web.Url));
message.Headers.Add(“X-Sharing-ItemId“, this.ConvertToBase64String(listItem.ID.ToString()));
SmtpClient client = new SmtpClient(webApp.OutboundMailServiceInstance.Server.Address);
client.Credentials = CredentialCache.DefaultNetworkCredentials;
client.Send(message);
return new object[] { true };
}
catch (Exception error)
{
return new object[] { false, error.Message }; }
}
string ConvertToBase64String(string InputString)
{
return “=?utf-8?B?” + System.Convert.ToBase64String(UTF8Encoding.UTF8.GetBytes(InputString)) + “?=“;
}
Note:
  • Any of the above mentioned solutions can be used based on the requirement. I have therefore listed out different approaches and I would leave it to your best judgement to decide on the selection of approach.
  • Above code is not a completely cleaned up code, you can remove unnecessary headers.
Hope this helps! Thank you for visiting my blog.