How To: Customizing alert emails using IAlertNotifyHandler


In my post last week I talked about customizing alert notifications and alert templates. Sometimes you need to go further and create an alert handler.  This week I’d like to share a code sample from Rashid Aga, one of our escalation engineers.  His sample demonstrates how to intercept and modify alert mails using the IAlertNotifyHandler interface.


 



Problem:


==============


There are issues with particular field names like ItemName which will be truncated in an alert email at 70 characters. There can also be situations where you want to embed additional content in the email or change the layout and email appearance altogether.


 


Solution:


==============


Make use of the IAlertNotifyHandler interface to intercept the email and modify it.


 


We can create our own class that inherits from the IAlertNotifyHandler interface and uses the OnNotification method. This will allow you to intercept the outgoing alert emails and modify them. We can access most of the properties for the alert and with some xml parsing and SharePoint object model code, we can extract all the information we need to build up the email. We can then construct the HTML stub to display the email based on your requirements and send the email out using SharePoint’s SendMail functionality.


 


Steps:


I have included the sample code below along with the steps to set up the scenario. I have formatted the output of my code to resemble the default alert template emails as close as possible, you can customize it further to suit your needs.


 


1      Create a class project that inhertits from the IAlertNotifyHandler interface. Include the Microsoft.SharePoint and Microsoft.SharePoint.Utilities namespaces in the project.


                    This is the code for the class:


    public class Class1:IAlertNotifyHandler


    {


 


        #region IAlertNotifyHandler Members


 


        public bool OnNotification(SPAlertHandlerParams ahp)


        {


            try


            {


                SPSite site = new SPSite(ahp.siteUrl+ahp.webUrl);


                SPWeb web = site.OpenWeb();


                SPList list=web.Lists[ahp.a.ListID];


                SPListItem item = list.GetItemById(ahp.eventData[0].itemId) ;


               


                string FullPath=HttpUtility.UrlPathEncode(ahp.siteUrl+”/”+ahp.webUrl+”/”+list.Title+”/”+item.Name);


                string ListPath = HttpUtility.UrlPathEncode(ahp.siteUrl + “/” + ahp.webUrl + “/” + list.Title);


                string webPath=HttpUtility.UrlPathEncode(ahp.siteUrl+”/”+ahp.webUrl);


                


                string build = “”;


                 if (ahp.eventData[0].eventType==1)


                 eventType=”Added”;


                 else if(ahp.eventData[0].eventType==2)


                 eventType=”Changed”;


                 else if(ahp.eventData[0].eventType==3)


                 eventType=”Deleted”;


 


                build = “<style type=\”text/css\”>.style1 {              font-size: small; border: 1px solid #000000;”+


                    “background-color: #DEE7FE;}.style2 {               border: 1px solid #000000;}</style></head>”+                    


                    “<p><strong>”+ item.Name.ToString() +”</strong> has been “+eventType +”</p>”+


                    “<table style=\”width: 100%\” class=\”style2\”><tr><td style=\”width: 25%\” class=\”style1\”>”+


                    “<a href=”+ webPath +”/_layouts/mysubs.aspx>Modify my Settings</a></td>”+


                    “<td style=\”width: 25%\” class=\”style1\”> <a href=”+ FullPath +”>View “+item.Name+”</a></td>”+


                    “<td style=\”width: 25%\” class=\”style1\”><a href=” + ListPath + “>View ” + list.Title + “</a></td>” +


                    ”        </tr></table>”;


                string subject=list.Title.ToString() ;              


                SPUtility.SendEmail(web,true , false, ahp.headers[“to”].ToString(), subject,build);


                return false;


            }


            catch (System.Exception ex)


            {


                return false;


            }


        }


 


        #endregion


    }


 


2.            GAC the dll. 


3.            Make a copy of the alertTemplates.xml file found at this location: C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\TEMPLATE\XML. Always work with a copy of AlertTemplates.xml, not the original.


4.            Call this new file CustomAlertTemplates and save the file. Edit the file and search for the keyword properties:


Include these additional lines into the properties block:


 


          <NotificationHandlerAssembly>AlertHandler, Version=1.0.0.0, Culture=neutral, PublicKeyToken=d59ecf2a3bd66904</NotificationHandlerAssembly>


          <NotificationHandlerClassName>AlertHandler.Class1</NotificationHandlerClassName>


    <NotificationHandlerProperties></NotificationHandlerProperties>


 


The entire stub should look like this now:


        <Properties>


            <ImmediateNotificationExcludedFields>ID;Author;Editor;Modified_x0020_By;Created_x0020_By;_UIVersionString;ContentType;TaskGroup;IsCurrent;Attachments;NumComments;</ImmediateNotificationExcludedFields>


            <DigestNotificationExcludedFields>ID;Author;Editor;Modified_x0020_By;Created_x0020_By;_UIVersionString;ContentType;TaskGroup;IsCurrent;Attachments;NumComments;</DigestNotificationExcludedFields>


            <NotificationHandlerAssembly>AlertHandler, Version=1.0.0.0, Culture=neutral, PublicKeyToken=d59ecf2a3bd66904</NotificationHandlerAssembly>


                <NotificationHandlerClassName>AlertHandler.Class1</NotificationHandlerClassName>


                <NotificationHandlerProperties></NotificationHandlerProperties>


  </Properties>


 


Include this xml stub in each alert template section you want in the alert template file.


 


5.            Run this command from C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\BIN:  stsadm -o updatealerttemplates -filename “C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\TEMPLATE\XML\customalerttemplates.xml” -url <your sharepoint site url>


6.            Run this command:  stsadm -o setproperty -pn job-immediate-alerts -pv “every 1 minutes” so that you can see the log file come back in one minute. Be sure to set the time back after testing.


7.            Make sure you have SharePoint already configured for outgoing emails.


8.            Make sure that you have alerts for the document library turned on if you are testing with the document library. 


9.            Run this command from the command prompt: iisreset


10.         Run this command from the command prompt: services.msc


11.         From the services window, restart the Windows SharePoint Services Timer.


 


Your custom email alert handler should be configured at this point. Create a new alert and you should get the updated custom email.


 


Once again, my thanks to Rashid for this sample.


 


Comments (23)

  1. Last month a customer asked me if they could modify SharePoint alert notifications? Of course you can

  2. Last month a customer asked me if they could modify SharePoint alert notifications? Of course you can

  3. subodh_pathak@hotmail.com says:

    Hi,

    I want to know how to use IAlertUpdateHandler class. My proble is to modify the alert messages sent during attaching the "Alert me".

    Thanks

  4. ibsooraj says:

    Hi,

    Implemented

    OnNotification(ByVal ahp As SPAlertHandlerParams) IAlertNotifyHandler.OnNotification

    For immediate alerts ahp.eventData.eventXml returns xml for relevant info related to modified item

    but for daily and weekly alerts ahp.eventData.eventXml  is empty. It returns <Fields></Fields>

    Help greatly appreciated

    Thanks

  5. Sivgee says:

    Hi,

    I followed your blog to create a custom handler to intercept the sharepoint alerts and modify the urls(ItemUrl and ListUrl for view item & View list) to a custom url and it worked for the first version of my assembly! But every time I drop an upadated version of my handler ,it never gets picked up and WSS seems to use the older version. I have tried

    – iisreset

    – restarting WSS timer

    – changing build  numbers and gac the new version

    Any ideas would be helpful.

  6. Despu&#233;s de mucho tiempo vuelvo a publicar un post con bastantes art&#237;culos interesantes, debido

  7. eddietec says:

    Hi All, do you know if we can change the Search alert template used by MOSS?

    Cheers.

  8. sumitdomyan says:

    How can I change email text when alert is created for a user?

    Thanks,

    Sumit

  9. Bizony&aacute;ra t&ouml;bben pr&oacute;b&aacute;lkoztak m&aacute;r azzal, hogyan lehet m&oacute;dos&iacute;tani

  10. maanu15 says:

    It does not work with Daily and Weekly  alerts…. It shows an either 0 or some numbers string in place of itemID and returns empty eventData.eventXml.

  11. Paul says:

    The newly created alerts can use the new updated email template. HOwever, how can i change the existing subscribed alerts to use the new template?

  12. Philip says:

    "ahp.eventData[0].eventType==3" should be "ahp.eventData[0].eventType==4".  Event better would be "(SPEventType)ahp.eventData[0].eventType == SPEventType.Delete;"

  13. Dirk says:

    Do you knwo if this will trap search alerts too?

    Search alerts have the template OSS.Search.

    Thanks

  14. Pavan says:

    I would appreciate if you can tell me in detail….Why we need to run teh Timer job after teh deployment.

    To be more specific…just in case timer services is in locked state, these custom alerts will not work?

    Thanks.

  15. Yasin says:

    Hello, Does this work on  sharepoint 2010?  I can't run please help me.

  16. Tanmay Mandal says:

    Hello Guys,

    I have requirement something same and some different is also there, I have to change sender address dynamically, first of all i should tell you what i am using ,

    WSS 3.0, Exchange server for email , but it has support for anonymous email sending from it's local network , i have done all these and for sending email i am using normal SMTP mail as i have to change sender address dynamically , who the user will post an item in list , mail will be send from his email address not from  the email, configured in central administration, I have followed full steps told here , except mail sending from System.Net.Mail, my problem is my dll is not working after following these steps , it is sending mail from default template.

    I found something blogs.syrinx.com/…/custom-alert-handlers-part-1-of-2.aspx

    in "Attaching the Template" section

    Not sure what is telling here , i mean what extra i have to do 🙁

    here is my code

    ————————————-

    using System;

    using Microsoft.SharePoint;

    using System.Web;

    using Microsoft.SharePoint.Utilities;

    using System.Net.Mail;

    using System.Collections;

    namespace HandleEmailAlerts

    {

       class EmailNotifierHelper : IAlertNotifyHandler

       {

           #region IAlertNotifyHandler Members

           public bool OnNotification(SPAlertHandlerParams ahp)

           {

               string eventType = String.Empty;

               try

               {

                   SPSite site = new SPSite(ahp.siteUrl + ahp.webUrl);

                   SPWeb web = site.OpenWeb();

                   SPList list = web.Lists[ahp.a.ListID];

                   SPListItem item = list.GetItemById(ahp.eventData[0].itemId);

                   //ahp.headers.Add("from", submittedBy.Email);

                   string FullPath = HttpUtility.UrlPathEncode(ahp.siteUrl + "/" + ahp.webUrl + "/" + list.Title + "/" + item.Name);

                   string ListPath = HttpUtility.UrlPathEncode(ahp.siteUrl + "/" + ahp.webUrl + "/" + list.Title);

                   string webPath = HttpUtility.UrlPathEncode(ahp.siteUrl + "/" + ahp.webUrl);

                   string build = "";

                   SPUser spUser=null;

                   if (ahp.eventData[0].eventType == 1)

                   {

                       eventType = "Added";

                       spUser = (SPUser)item["Created By"];

                   }

                   else if (ahp.eventData[0].eventType == 2)

                   {

                       eventType = "Changed";

                       spUser = (SPUser)item["Modified by"];

                   }

                   else if (ahp.eventData[0].eventType == 3)

                   {

                       eventType = "Deleted";

                       spUser = (SPUser)item["Modified by"];

                   }

                   build = "</head>" + "<p><strong>" + item.Name.ToString() + "</strong> has been " + eventType + "</p>" + "<table style="width: 100%" class="style2"><tr><td style="width: 25%" class="style1">" + "<a href=" + webPath + "/_layouts/mysubs.aspx>Modify my Settings</a></td>" + "<td style="width: 25%" class="style1"> <a href=" + FullPath + ">View " + item.Name + "</a></td>" + "<td style="width: 25%" class="style1"><a href=" + ListPath + ">View " + list.Title + "</a></td>" + "        </tr></table>";

                   string subject = list.Title.ToString();

                   //SPUtility.SendEmail(web, true, false, ahp.headers["to"].ToString(), subject, build);

                   SendMail(subject, build, spUser.Email, ahp);

                   return false;

               }

               catch (System.Exception ex)

               {

                   return false;

               }

           }

           /// <summary>

           /// Send mail from SMTP

           /// </summary>

           /// <param name="subject"></param>

           /// <param name="body"></param>

           /// <param name="from"></param>

           /// <param name="ahp"></param>

           private void SendMail(string subject, string body, string from, SPAlertHandlerParams ahp)

           {

               try

               {

                   MailMessage mMessage = new MailMessage();

                   mMessage.Subject = subject;

                   mMessage.Body = body;

                   mMessage.From=new MailAddress(from);

                   mMessage.To.Add(ahp.headers["to"].ToString());

                   mMessage.IsBodyHtml = true;

                   mMessage.Priority = MailPriority.High;

                   SmtpClient mSmtpClient = new SmtpClient();

                   System.Net.NetworkCredential credential = new System.Net.NetworkCredential("spemail@myserver.com", "password");

                   mSmtpClient.Credentials = credential;

                   mSmtpClient.Host = "mail.haifire.com";

                   mSmtpClient.Port = 25;

                   mSmtpClient.Send(mMessage);

               }

               catch (Exception ex)

               {

               }

           }

           #endregion

       }

    }

    ——————————————————–

    You may think

    System.Net.NetworkCredential("spemail@myserver.com", "password");

                   mSmtpClient.Credentials = credential;

    these are the cause of problem, i have removed that as my email server support anonymous mailing , but problem remain, mail is going through the default template and from address is default email address.

    I need urgent help as my client is waiting for long time and i have consulted with some people working on the domain but :(,

    Guy's, please help me to complete the Job,

    Thanks in advance

    Thanks and regards

    Tanmay Mandal

  17. g.zanghi@gmail.com says:

    if eventType= 4 (deleted) not use

    SPListItem item = list.GetItemById(ahp.eventData[0].itemId) ;

    item no longer exists

    throw exception.

    Thanks for posting.

  18. Tanmay Mandal says:

    Hello Guys,

    I have posted details status

    social.msdn.microsoft.com/…/c02d005f-9821-4adb-aa88-5a34fe080f48

    not sure what is going on there, is that any kind of permission issue , why my template is not used by SP? code is same i have done as given here just i have some part of customization, and after that i also write log if it is calling the dll :(, bad news is it is not calling my dll for sending mail 🙁

    I will do post of my code in next comment

  19. Tanmay Mandal says:

    Hi

    here is new code in my last poste

    social.msdn.microsoft.com/…/c02d005f-9821-4adb-aa88-5a34fe080f48

    problem remains

    Please help .

    thanks and regards

    Tanmay Mandal

  20. Noble says:

    Hello,

    Can someone please help – how can I complete the 1st step; I am new to Visual studio

     Create a class project that inhertits from the IAlertNotifyHandler interface. Include the Microsoft.SharePoint and Microsoft.SharePoint.Utilities namespaces in the project.

    Appreciate the assistance

    Thanks

  21. Kevin says:

    What do you mean by " GAC the dll"? What does that mean in terms of SharePoint 2013? Thanks!