Wednesday, June 20, 2012

Configurable SharePoint solution for Sending Email Alerts upon Document/List Item Expiration


Problem: need to develop a configurable sharepoint solution that would do the following:
- be deployed to any SharePoint Site as an Event receiver 
- Once the Event Receiver (ER) is attached to a List/Document Library, it will send Email Alerts a certain number of days before the Document/List Item Expiration Date added by User upon Document Upload/List Item Creation

Why Event Receiver? Explained at the end of the post.

Solution: The Event Receiver, once fired after a list item has been added, will do the following:
1) Fire a connection to a configuration list, lets call it DocumentExpirationConfig List.
2) Find out the list name it is currently fired on using properties.ListTitle, and then using a CAML Query, find the List Item in DocumentExpirationConfig List that corresponds to that List.
3) Once a record has been obtained the ER can find the name of the Column it has to read for the Document Expiration Date, subtract the number of days (once again read from the ConfigurationList) before which it should send the Alert from the Document Expiration Date, , and then set the value of the Destination Column(let's call it, for instance, EmailAlertDate) with that Date (once again read from the ConfigurationList) 

for example: Document Expiration Date - 90 (number of days to send the Alert before expiration)  = EmailAlertDate
The Document Expiration Config List is as shown in the screenshot below:


As you can tell, the DocumentExpirationConfig makes the ER configurable and deployable to any list in the site, without requiring any code changes.

After a record has been added, and the ER fired on it, it would look something like the screenshot below:


The code for the ER is shown below, simply call this method in the ItemAdded and ItemUpdated Event Handlers:
 1:  public void UpdateExpirationAlertColumn(SPItemEventProperties properties, bool isadded)
 2:  {
 3:  try
 4:  { 
 5:  SPList _configlist = properties.Web.Lists.TryGetList("DocumentExpirationConfig");
 6:  string _documentexpirationcolumn = string.Empty;
 7:  string _expirationalertcolumn = string.Empty;
 8:  if (_configlist != null)
 9:  {
 10:  string _camlQuery = "" +properties.ListTitle + "";
 11:  SPQuery _query = new SPQuery();
 12:  _query.Query = _camlQuery;
 13:  SPListItemCollection _listitems = _configlist.GetItems(_query);
 14:  
 15:  if (_listitems.Count > 0)
 16:  {
 17:  _documentexpirationcolumn = _listitems[0]["DocumentExpirationColumn"].ToString();
 18:  _expirationalertcolumn = _listitems[0]["ExpirationAlertColumn"].ToString();
 19:  
 20:  if (properties.ListItem[_documentexpirationcolumn] != null)
 21:  {
 22:  DateTime _documentexpiratedate = DateTime.Parse(properties.ListItem[_documentexpirationcolumn].ToString());
 23:  properties.ListItem[_expirationalertcolumn] = _documentexpiratedate.AddDays(-60).ToShortDateString();
 24:  properties.ListItem.SystemUpdate();
 25:  }
 26:  
 27:  }
 28:  
 29:  }
 30:  }
 31:  catch (Exception ex)
 32:  {
 33:  EventLog m_EventLog = new EventLog("");
 34:  m_EventLog.Source = "Error updating Document Expiration Date";
 35:  m_EventLog.WriteEntry("Error updating Document Expiration Date" + ex.Message + ex.StackTrace,
 36:  EventLogEntryType.FailureAudit);
 37:  }
 38:  
 39:  }

- Once the ER has finished updating the EmailAlertDate, the next step is find a way to send an alert regarding the expiration of the document/list item to the User who created the document. This could be done in either of two ways

Approach #1) Create a Timerjob that runs each night and figures out all the documents/list items that are expiring on that day, and send an Alert to users.
Approach #2) Create a Retention Policy that kicks off a Workflow, that checks if Today's Date = EmailAlertDate, then sends the Alert to users, informing them about the Contract Expiration.

I chose the second approach, as shown in the screenshot below:


Why EventReceiver?: In case you are wondering why I chose to add an Event Receiver, here are the reasons why:
First of all, SharePoint does not allow one to kickoff a Retention policy a certain number of days before a certain datetime value (read from a column such as the Document Expiration Date column described above). As you can see, in the screenshot above, there is a '+' sign but no '-' sign. Thus, for example, we cannot kick off this policy  30 days before Document Expiration Date ( I wish that was true :-)).
So you might ask, why not reate a calculated column with the same value set by the Event Receiver. Well, the answer to that is, yes, you could very well set the value of a calculated column without any need of an ER, but SharePoint will not allow you to kick off a Retention policy on it. It does not show up in the drop down list of columns on the Retention Stage Properties page, as shown in the screenshot above. 
Thus, one way around the above two problems is to use the Event Receiver as described above.

No comments: