SharePoint SendEmail Activity “Go to My Tasks”

In Microsoft.SharePoint.WorkflowActions.SendEMail Acitivity, there is a property called IncludeStatus http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.workflowactions.sendemail.includestatus.aspx.  When this property is set to true, in the Email that we receive through SendEMail Acitivity will include two links.

1) View Workflow Summary

2) Go to My Tasks

Each of these links takes us to the appropriate page based on the generated URL. The link for View Workflow Summary is constructed correctly, but for Go to My Tasks is not correct.

For e.g

The Workflow Summary URL is correctly setup, pointing to http://myServer.com/Home/_layouts/WrkStat.aspx?List=62d46228-4188-49e5-90f2-31245864b03b&WorkflowInstanceID=234b7864-c37d-42d0-b2bb-964d15cb67a2

For Go to my tasks URL is incorrect setup, pointing to http://myServer.com/SiteA/SiteB/SiteA/SiteB/Lists/Tasks/AllItems.aspx.  The problem being the "SiteA/SiteB” being twice in this case. The link may vary depending on Site Collection level, Site level or Managed property defined.

The Interface type for the send Email action was set to Microsoft.SharePoint.Workflow.ISharePointService. In the SharePoint dll's SPWinOEWSSService class implements this interface.  The Send Email method of this class (SendEmail(Guid workflowId, bool includeStatus, StringDictionary headers, string body)) contains an error where it will incorrectly set the URL.

public void string str4 = parentWeb.Url + currentWorkflow.TaskList.DefaultViewUrl;

parentWeb.Url Equals http://myServer.com/SiteA/SiteB

currentWorkflow.TaskList.DefaultViewUrl Equals /SiteA/SiteB /Lists/AllItems.aspx

In order to fix this issue, we can write a custom activity similar to SendEmail activity and change the URL generated for “Go to My Tasks”

1.  In the Main Workflow code file, have these properties declared.

 public Guid workflowId = default(System.Guid);
 public SPWorkflowActivationProperties workflowProperties = new SPWorkflowActivationProperties();

2. Code snippet in OnWorkflowActivated Event

 Activity1.ItemId = workflowProperties.ItemId;
 Activity1.LibId = workflowProperties.ListId;
 Activity1.WebId = workflowProperties.WebId;
 Activity1.SiteId = workflowProperties.SiteId;
 Activity1.WorkflowId = workflowProperties.WorkflowId;

3. Custom Activity code file, variable declarations

 public static int ItemId;
 public static Guid LibId;
 public static Guid WebId;
 public static Guid SiteId;
 public static Guid WorkflowId;

4. Dependency Property declarations

 #region Dependency_Properties
         //BCC
  
         public static DependencyProperty BCCProperty = DependencyProperty.Register("BCC", typeof(System.String), typeof(SendEmailActivity.Activity1));
  
         [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
         [BrowsableAttribute(true)]
         [CategoryAttribute("Misc")]
         public String BCC
         {
             get
             {
                 return ((System.String)(base.GetValue(SendEmailActivity.Activity1.BCCProperty)));
             }
             set
             {
                 base.SetValue(SendEmailActivity.Activity1.BCCProperty, value);
             }
         }
  
         //Body
  
         public static DependencyProperty BodyProperty = DependencyProperty.Register("Body", typeof(System.String), typeof(SendEmailActivity.Activity1));
  
         [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
         [BrowsableAttribute(true)]
         [CategoryAttribute("Misc")]
         public String Body
         {
             get
             {
                 return ((System.String)(base.GetValue(SendEmailActivity.Activity1.BodyProperty)));
             }
             set
             {
                 base.SetValue(SendEmailActivity.Activity1.BodyProperty, value);
             }
         }
  
         //CC
  
         public static DependencyProperty CCProperty = DependencyProperty.Register("CC", typeof(System.String), typeof(SendEmailActivity.Activity1));
  
         [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
         [BrowsableAttribute(true)]
         [CategoryAttribute("Misc")]
         public String CC
         {
             get
             {
                 return ((System.String)(base.GetValue(SendEmailActivity.Activity1.CCProperty)));
             }
             set
             {
                 base.SetValue(SendEmailActivity.Activity1.CCProperty, value);
             }
         }
  
         //From
         public static DependencyProperty FromProperty = DependencyProperty.Register("From", typeof(System.String), typeof(SendEmailActivity.Activity1));
  
         [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
         [BrowsableAttribute(true)]
         [CategoryAttribute("Misc")]
         public String From
         {
             get
             {
                 return ((System.String)(base.GetValue(SendEmailActivity.Activity1.FromProperty)));
             }
             set
             {
                 base.SetValue(SendEmailActivity.Activity1.FromProperty, value);
             }
         }
  
         //Header
         public static DependencyProperty HeaderProperty = DependencyProperty.Register("Header", typeof(System.String), typeof(SendEmailActivity.Activity1));
  
         [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
         [BrowsableAttribute(true)]
         [CategoryAttribute("Misc")]
         public String Header
         {
             get
             {
                 return ((System.String)(base.GetValue(SendEmailActivity.Activity1.HeaderProperty)));
             }
             set
             {
                 base.SetValue(SendEmailActivity.Activity1.HeaderProperty, value);
             }
         }
  
         //IncludeStatus
         public static DependencyProperty IncludeStatusProperty = DependencyProperty.Register("IncludeStatus", typeof(System.Boolean), typeof(SendEmailActivity.Activity1));
  
         [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
         [BrowsableAttribute(true)]
         [CategoryAttribute("Misc")]
         public Boolean IncludeStatus
         {
             get
             {
                 return ((System.Boolean)(base.GetValue(SendEmailActivity.Activity1.IncludeStatusProperty)));
             }
             set
             {
                 base.SetValue(SendEmailActivity.Activity1.IncludeStatusProperty, value);
             }
         }
  
         //Subject
         public static DependencyProperty SubjectProperty = DependencyProperty.Register("Subject", typeof(System.String), typeof(SendEmailActivity.Activity1));
  
         [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
         [BrowsableAttribute(true)]
         [CategoryAttribute("Misc")]
         public String Subject
         {
             get
             {
                 return ((System.String)(base.GetValue(SendEmailActivity.Activity1.SubjectProperty)));
             }
             set
             {
                 base.SetValue(SendEmailActivity.Activity1.SubjectProperty, value);
             }
         }
  
         //To
         public static DependencyProperty ToProperty = DependencyProperty.Register("To", typeof(System.String), typeof(SendEmailActivity.Activity1));
  
         [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
         [BrowsableAttribute(true)]
         [CategoryAttribute("Misc")]
         public String To
         {
             get
             {
                 return ((System.String)(base.GetValue(SendEmailActivity.Activity1.ToProperty)));
             }
             set
             {
                 base.SetValue(SendEmailActivity.Activity1.ToProperty, value);
             }
         }
         //MethodInvoking
         public static DependencyProperty MethodInvokingEvent = DependencyProperty.Register("MethodInvoking", typeof(System.EventHandler), typeof(SendEmailActivity.Activity1));
  
         [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
         [BrowsableAttribute(true)]
         [CategoryAttribute("Handlers")]
         public event EventHandler MethodInvoking
         {
             add
             {
                 base.AddHandler(MethodInvokingEvent, value);
             }
             remove
             {
                 base.RemoveHandler(MethodInvokingEvent, value);
             }
         }
  
         //InterfaceType
         public static DependencyProperty InterfaceTypeProperty = DependencyProperty.Register("InterfaceType", typeof(System.String), typeof(SendEmailActivity.Activity1));
  
         [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
         [BrowsableAttribute(true)]
         [CategoryAttribute("Activity")]
         public String InterfaceType
         {
             get
             {
                return "Microsoft.SharePoint.Workflow.ISharePointService";
             }
             
         }
  
         //MethodName
         public static DependencyProperty MethodNameProperty = DependencyProperty.Register("MethodName", typeof(System.String), typeof(SendEmailActivity.Activity1));
  
         [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
         [BrowsableAttribute(true)]
         [CategoryAttribute("Activity")]
         public String MethodName
         {
             get
             {
                return "SendEmail";
             }
  
         }
  
         //CorrelationToken
         public static DependencyProperty CorrelationTokenProperty = DependencyProperty.Register("CorrelationToken", typeof(System.String), typeof(SendEmailActivity.Activity1));
  
         [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
         [BrowsableAttribute(true)]
         [CategoryAttribute("Activity")]
         
         public String CorrelationToken
         {
             get
             {
                 return ((System.String)(base.GetValue(SendEmailActivity.Activity1.CorrelationTokenProperty)));
             }
             set
             {
                 base.SetValue(SendEmailActivity.Activity1.CorrelationTokenProperty, value);
             }
  
         }
  
         //OwnerActivityName
         public static DependencyProperty OwnerActivityNameProperty = DependencyProperty.Register("OwnerActivityName", typeof(System.String), typeof(SendEmailActivity.Activity1));
  
         [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
         [BrowsableAttribute(true)]
         [CategoryAttribute("Activity")]
         public String OwnerActivityName
         {
             get
             {
                 return ((System.String)(base.GetValue(SendEmailActivity.Activity1.OwnerActivityNameProperty)));
             }
             set
             {
                 base.SetValue(SendEmailActivity.Activity1.OwnerActivityNameProperty, value);
             }
  
         }
  
  
         #endregion

5. ExecudeCode method of code activity in custom activity.

 SendEmail sE = new SendEmail();
 sE.From = From; 
 sE.To = To;
 sE.Subject = Subject ;
 sE.Body = Body; 
 CorrelationToken ct = new CorrelationToken(CorrelationToken);
 ct.OwnerActivityName = OwnerActivityName;
 sE.CorrelationToken = ct;
 sE.IncludeStatus = IncludeStatus;
  
  
 SPSite site = new SPSite(SiteId);
 SPWeb web = site.OpenWeb(WebId);
 SPList list = web.Lists[LibId];
 SPListItem item = list.GetItemById(ItemId); 
 SPWorkflow currentWorkflow = item.Workflows[WorkflowId];
 StringDictionary headers = new StringDictionary();
 SPWeb parentWeb = currentWorkflow.ParentList.ParentWeb;
 string str = SPResource.GetString("DirectionDirValue", new object[0]);
 string str2 = headers["subject"];
 string str3 = parentWeb.Url + "/" + currentWorkflow.ParentAssociation.StatusUrl + "?List=" + currentWorkflow.ParentList.ID.ToString() + "&WorkflowInstanceID=" + currentWorkflow.InstanceId.ToString();
 //string str4 = parentWeb.Url + currentWorkflow.TaskList.DefaultViewUrl;
 int sIndex = currentWorkflow.TaskList.DefaultViewUrl.IndexOf("/Lists"); // Depending on the URL, the logic can be changed
 string str4 = parentWeb.Url + currentWorkflow.TaskList.DefaultViewUrl.Substring(sIndex);
 string body = sE.Body;
 body = string.Format(CultureInfo.InvariantCulture, SPResource.GetString("WorkflowChannelEmailHeader", new object[0]), new object[] { str, str2, str3, str4, body });
 SPUtility.SendEmail(web, true, false, sE.To, sE.Subject, body);

That’s all we have to do!  Use the custom activity in the workflow and set its properties.  By setting IncludeStatus property to true, and then by running the workflow, we will get a wonderful email with correct URL generated for “Go to My Tasks” link!!