views:

421

answers:

1

I'm currently running a publishing portal in a small server farm environment. Using the page settings and schedule form for publishing pages we have configured our content to 'send a content review request mail to the page contact'. We've tried a number of different configurations for the frequency of the emails but no matter what we select, no emails ever get sent. The same thing appears to be happening to the expiry notifications.

We've checked the email settings for the farm and they appear to be correct. Alerts and welcome emails are all functioning correctly. Does anyone know how to get these working?

A: 

After some investigation with Reflector we eventually discovered the reason why the emails weren't being sent out (and why they never would no matter what we changed in the settings)

The review and expiry notifications operate through the combination of an event handler, a sharepoint timer job definition and a custom list called Notification Pages / Notification List. The basic order of events is as follows:

  1. During the process of autoring a new content page, a user selects to have a review or expiry notification sent to them at a particular point in time. The content page is subsequently checked in and published.
  2. The event handler (ScheduledItemEventReceiver) is fired and verifies that the item in question is a ScheduledItem and that it is in the process of being approved. If this is the case then it will tell the item to register it's schedule (ScheduledItem.Schedule(...)).
  3. This process takes care of the scheduled start and end dates that have been specified for the item, ensuring that it becomes available at the correct time. In addition it should add an item to the Notification List (http://[Site Name]/Notification Pages/).
  4. The Timer Job (NotificationJobDefinition) will periodically query the items in the Notification List and if the Delivery Date has passed it will send either the review or expiry notification email to the page contact.

So this all sounds fine and in theory should work perfectly, but there is a problem. In order to add the item to the Notification List, the ScheduledItem.Schedule method calls the HandleScheduling method.

The HandleScheduling method for a PublishingPage (inherits from ScheduledItem) will call UpdateNotificationList which in turn adds an item to the Notification List. The HandleScheduling method for the base ScheduledItem class is empty.

The problem, it would seem, is that the ScheduledItemEventReceiver class instantiates it's objects as ScheduledItem (the base class) and so whenever it calls HandleScheduling, nothing happens. You can browse to the Notification List (/Notification Pages/AllItems.aspx - requires site collection admin permissions) and it is completely empty.

We currently have a workaround in place. We developed and deployed a custom event receiver which replaces the ScheduledItemEventReceiver. It checks to see if the item is a publishing page and if it is, uses some reflection in order to call the UpdateNotificationList method directly. With this in place we started to see items being added into the notification list as expected.

public class ScheduledPageEventReceiver : SPItemEventReceiver
{
    protected void HandleScheduling(PublishingPage page)
    {
        Type t = typeof(PublishingPage);
        MethodInfo notificationMethod = t.GetMethod("UpdateNotificationList",BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.InvokeMethod);
        if (notificationMethod != null)
        {
            notificationMethod.Invoke(page, null);
        }
    }

    public override void ItemUpdating(SPItemEventProperties properties)
    {
        if (properties == null)
        {
            throw new ArgumentNullException("properties");
        }
        if (properties.AfterProperties == null)
        {
            throw new ArgumentNullException("properties.AfterProperties");
        }
        object status = properties.AfterProperties["vti_doclibmodstat"];
        if ((status != null) && (Convert.ToInt32(status, CultureInfo.InvariantCulture) == 0)) //Approved
        {
            using (SPWeb web = properties.OpenWeb())
            {
                SPListItem item = web.GetFile(properties.BeforeUrl).Item;
                if (PublishingPage.IsPublishingPage(item) && PublishingPage.IsScheduledItem(item))
                {
                    PublishingPage page = PublishingPage.GetPublishingPage(item);
                    HandleScheduling(page);
                    return; 
                }
            }
        }
    }
}
edwach