Thursday, January 12, 2012

Sending Emails to SharePoint Group

Recently, I came across a situation where I had to include SharePoint group in To field of “Send Email” activity in a reusable workflow designed in SharePoint Designer. I just included it thinking that it would work (just like hundreds of other developers I guess) but I was wrong. Well, that was my last activity in the workflow. After it was deployed, it would NOT send emails to members of the SharePoint Group and worse than that, it would not show any error, the workflow appears completed but it does NOT terminate itself but the page gets published. As a result, content authors cannot start a new workflow because previous workflow was not terminated even though item was published. SharePoint not sending emails is understood but I would be happier it it logged something in the workflow history or terminated the workflow. It took me many change/deploy cycles before I could figure it out.

I posted a question on here: Definitive answer to sending emails to SP Group from Workflow and on MSDN forum too, but did not get an answer for couple of days and then thought about figuring out solution that works for me (yes, there could be other solutions out there).

Solution and Assumptions: It was safe to assume in my situation that SharePoint users will directly be added to the group to which I need to send emails.

So the simplest solution was to get develop a custom activity which can be consumed by SharePoint designer. The activity outputs list of emails given the SharePoint group or individual’s name. The designer can take the output and store it in Workflow variable. And finally, the variable is used in “To” field of the Send Email Activity.

So following solution needs to be revisited (or tested) if the SharePoint group includes other groups or active directory groups.

Code

Here is my activity looks like:

using System;
using System.ComponentModel;
using System.Linq;
using System.Workflow.ComponentModel;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Utilities;
using Microsoft.SharePoint.Workflow;
using Microsoft.SharePoint.WorkflowActions;
namespace MyProduct.Workflows.Activities
{
public class ExpandSharePointGroup : Activity
{
public static DependencyProperty __ContextProperty = System.Workflow.ComponentModel.DependencyProperty.Register("__Context",
typeof(WorkflowContext), typeof(ExpandSharePointGroup));

[Description(
"Context")]
[Browsable(
true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public WorkflowContext __Context
{
get
{
return ((WorkflowContext)(base.GetValue(__ContextProperty)));
}
set
{
base.SetValue(__ContextProperty, value);
}
}


public static DependencyProperty GroupNameProperty = DependencyProperty.Register("GroupName",
typeof(string), typeof(ExpandSharePointGroup));

[Description(
"SharePoint Group Name")]
[Category(
"MyProduct Workflow Activities")]
[Browsable(
true)]
[DesignerSerializationVisibility
(DesignerSerializationVisibility.Visible)]
public string GroupName
{
get
{
return ((string)
(
base.GetValue(GroupNameProperty)));
}
set
{
base.SetValue(GroupNameProperty, value);
}
}

public static DependencyProperty FieldValueProperty = DependencyProperty.Register("FieldValue",
typeof(string), typeof(ExpandSharePointGroup));

[Description(
"Field Value")]
[Category(
"MyProduct Workflow Activities")]
[Browsable(
true)]
[DesignerSerializationVisibility
(DesignerSerializationVisibility.Visible)]
public string FieldValue
{
get
{
return ((string)
(
base.GetValue(FieldValueProperty)));
}
set
{
base.SetValue(FieldValueProperty, value);
}
}



protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
{

SPWeb web
= (SPWeb)__Context.Web;

try
{
if (string.IsNullOrEmpty(GroupName))
{

return ActivityExecutionStatus.Closed;
}

string strOutput = string.Empty;
strOutput
= Helper.ResolveToEmailName(__Context, GroupName);
FieldValue
= strOutput;
}
catch (Exception ex)
{
// TODO: Log error here
return ActivityExecutionStatus.Faulting;
}


return ActivityExecutionStatus.Closed;
}

}

}

In order to make sure that above activity is available to SharePoint designer, we need to deploy a .Actions file to {SharePointRoot}\Template\1033\Workflow which is shown below:


<?xml version="1.0" encoding="utf-8"?>
<WorkflowInfo Language="en-us">
<Actions>
<Action Name="Expand SharePoint Group Members"
ClassName
="FULL CLASS NAME"
Assembly
="FULL ASSEMBLY NAME"
AppliesTo
="all"
Category
="My Custom Workflow Activities">
<RuleDesigner Sentence="Expand Email for %1 it in: %2">
<FieldBind Field="GroupName" Text="SharePoint Group" DesignerType="TextBox" Id="1"/>
<FieldBind Field="FieldValue" Text="Field Value" DesignerType="ParameterNames" Id="2"/>
</RuleDesigner>
<Parameters>
<Parameter Name="__Context" Type="Microsoft.SharePoint.WorkflowActions.WorkflowContext" Direction="In" DesignerType="Hide" />
<Parameter Name="GroupName" Type="System.String, mscorlib" Direction="In" />
<Parameter Name="FieldValue" Type="System.String, mscorlib" Direction="Out" />
</Parameters>
</Action>
</Actions>
</WorkflowInfo>

Finally, you need to add a web.config entry under authorizedTypes section:



<authorizedType Assembly="Full Assembly Name" Namespace="Your Name space" TypeName="Class Name or *" Authorized="True" />


Note: After your assembly is deployed in GAC, Actions file is deployed on SharePoint root and web.config entry is added (as shown above), you need to close the SharePoint Designer and open it again before you can see your activity in list of available actions.


Hope this helps!

1 comment:

  1. Thanks for sharing your article and for giving us the chance to read it. It is very helpful and encouraging. Visit my site too.

    triciajoy.com

    www.triciajoy.com

    ReplyDelete