My client needed a customized alert created each time a new issue was added to a standard Issues list. The only difference from out-of-the-box alert functionality was that customized alert Email message needed to have an Issue ID in its subject. I haven’t customized alerts before so I did some research, which showed that:
- you can customize HTML of an alert through alert templates and use placeholders to insert values in an Email message.
- there is an API letting you to tap into alert message processing pipeline and customize Email message before it is sent out.
There is a lot of information online on the subject, yet I still had difficulties with this seemingly easy problem. The following resources were most useful to me: MSDN (http://msdn.microsoft.com/en-us/library/bb802949.aspx), Albert Meerscheidt’s post about alerts in WSS 3.0 and Yaroslav Pentsarskyy’s post about customizing alerts in SharePoint 2010.
For me empowered with this information the task came down to writing a correct alert template, or so I thought. Take a look at this fragment of an out-of-the-box immediate alert template defining Email message subject text (immediate alerts are sent right away while digest alerts are sent later as a summary):
<Subject><GetVar Name="AlertTitle" />
<HTML><![CDATA[ - ]]></HTML>
<GetVar Name="ItemName" />
</Subject>
The interesting part here is placeholders “AlertTitle” and “ItemName” and the way they are used. I have a field named “ID” (it is a part of a standard Issues list), and a naive approach of writing <GetVar Name=”ID” /> didn’t get me anywhere. Same result with adding a custom text column named “ATextColumn” and then doing <GetVar Name=”ATextColumn” />. Well, the <GetVar> element is a part of CAML Vew Schema and yields a value of a local or a global variable set in current page context, but what are these placeholders and how are they set? At this point I have realized that my effort estimates were a little too optimistic. Then I bumped into a help article about alerts in WSS 2.0. Among other things it had a list of “tags” that could be included in alert templates. Here it is:
Tag | Description |
SiteUrl | The full URL to the site. |
SiteName | The name of the site. |
SiteLanguage | The locale ID (LCID) for the language used in the site.
For example, 1033 for U.S. English. |
AlertFrequency | Immediate (0), Daily (1), or Weekly (2). |
ListUrl | The full URL to the list. |
ListName | The name of the list. |
ItemUrl | The full URL to the item. |
ItemName | The name of the item. |
EventType | ItemAdded (1), Item Modified (2), Item Deleted (4), DiscussionAdded (16),
Discussion Modified (32), Discussion Deleted (64), Discussion Closed (128), Discussion Activated (256). |
ModifiedBy | The name of the user who modified an item. |
TimeLastModified | The time the item was last modified. |
MySubsUrl | The full URL to the My Alerts on this Site page in Site Settings. |
Some of these tags are used in the out-of-the-box templates. I tried the rest of them and all have worked. So it appears as we are limited to using these 12 tags only, and that it is an old functionality which survived WSS 2.0, WSS 3.0 and SharePoint Foundation 2010 releases. If someone knows more about it please post a comment to validate, disprove or complete this statement.
Great, but how do I get the ID into my Email’s subject? I don’t want to list a bunch of fields in my subject, just the ID, so I don’t want to use <Fields> element there. The API did the trick. I have created a class implementing IAlertNotifyHandler interface and used regular expressions to replace a placeholder with a value:
public class MessageCustomizer : IAlertNotifyHandler
{
public bool OnNotification(SPAlertHandlerParams parameters)
{
string webUrl = parameters.siteUrl + parameters.webUrl;
using (SPSite site = new SPSite(webUrl))
using(SPWeb web = site.OpenWeb())
{
string to = parameters.headers["To"];
string subjectTemplate = parameters.headers["Subject"];
string itemId = parameters.eventData[0].itemId.ToString();
//
// Below we are replacing a placeholder we have
// created in our alert template with the actual value.
//
string subject = Regex.Replace(
subjectTemplate,
"#ID#",
itemId,
RegexOptions.IgnoreCase);
bool result = SPUtility.SendEmail(
web,
false,
false,
to,
subject,
parameters.body);
return result;
}
}
}
We still need a customized alert template – firstly to insert our own custom placeholder (in my example #ID#) and secondly to register the MessageCustomizer class so its OnNotification() method would get called. Here is updated fragment defining Email’s subject:
<Subject>
<HTML><![CDATA[Issue ID #ID#: ]]></HTML>
<GetVar Name="AlertTitle" />
<HTML><![CDATA[ - ]]></HTML>
<GetVar Name="ItemName" />
</Subject>
Registration of MessageCustomizer class and its assembly is done inside of <NotificationHandlerClassName> and <NotificationHandlerAssembly> elements of the template:
<NotificationHandlerAssembly>AlertCustomization, Version=1.0.0.0, Culture=neutral, PublicKeyToken=bda7bcef852778f0</NotificationHandlerAssembly>
<NotificationHandlerClassName>AlertCustomization.MessageCustomizer</NotificationHandlerClassName>
So we are arriving at a standard “It depends…” answer to the question of whether to customize alerts via templates or via code. Regardless of which approach works for you for any such customization that is not an ad hoc fix or a proof of concept you are looking into creating a package including deployment script, a SharePoint solution and possibly a feature with feature receiver. The functionality is almost identical between WSS 3.0 and SharePoint Foundation 2010 with the latter adding SMS support. Also with Visual Studio 2010 it is much easier to package things, yet you are probably still looking into a few hours of work to get it done right.