Second Life of a Hungarian SharePoint Geek

October 26, 2012

How to populate the Attendees field of a SharePoint event based on the addressees of a meeting request? (Version 2)

In my previous post I already demonstrated a method to resolve the meeting attendees based on the mail addresses in the incoming mail, though – as I wrote there – that method has issues with event updates.

Note: In this post I show you an alternative, that – at least, based on my experience – performs better. However, the code below uses non-public API calls and accesses SharePoint database directly, so it is not a supported approach. Use this sample at you own risk and preferably only in test environments.

In this version of implementation we alter the standard pipeline of incoming mail processing for our calendar to inject our code into the process. To achieve that, we create an a SPEmailHandler that first invokes the ProcessMessage method of the SPCalendarEmailHandler class to achieve the standard functionality, then resolves the attendees using the To mail header property based on this technique, and updates the related item / all related items (in the case of a recurring event, it may be not a single item) in the list.

Note: In the case of the To mail header property we don’t need to unescape the value, so you should comment out this line of code in the GetUsersByMailTo method introduced in the first part of this post:

emailTo = emailTo.Replace("&lt;", "<").Replace("&gt;", ">");

We can get the corresponding item(s) based the unique identifier (UID, you can read details on Wikipedia) vCalendar property of the event using the GetCalendarProp method described in my former post. We use the GetExistingItems method below to get these related items:

  1. private SPListItemCollection GetExistingItems(SPList list, string uid)
  2. {            
  3.     SPQuery query = new SPQuery();
  4.     query.Query = "<Where><Eq><FieldRef Name=\"" + list.Fields[SPBuiltInFieldId.EmailCalendarUid].InternalName + "\"/><Value Type=\"Text\">" + SPEncode.HtmlEncode(uid) + "</Value></Eq></Where>";
  5.     SPListItemCollection existingItems = list.GetItems(query);
  6.     return existingItems;
  7. }

The following method allows us to invoke the ProcessMessage method of the SPCalendarEmailHandler class:

  1. private void ProcessMessage(SPList list, SPEmailMessage emailMessage)
  2. {
  3.     Trace.TraceInformation("Starting SPCalendarEmailHandler processing");
  4.  
  5.     string spCalendarEmailHandlerTypeName = "Microsoft.SharePoint.SPCalendarEmailHandler";
  6.  
  7.     // hack to get the Microsoft.SharPoint assembly
  8.     Assembly sharePointAssembly = typeof(SPWeb).Assembly;
  9.     // and a reference to the type of the SPCalendarEmailHandler internal class
  10.     Type spCalendarEmailHandlerType = sharePointAssembly.GetType(spCalendarEmailHandlerTypeName);
  11.  
  12.     // spCalendarEmailHandler will be of type internal class
  13.     // Microsoft.SharePoint.SPCalendarEmailHandler
  14.     // defined in Microsoft.SharePoint assembly
  15.     object spCalendarEmailHandler = sharePointAssembly.CreateInstance(spCalendarEmailHandlerTypeName, false,
  16.         BindingFlags.Public | BindingFlags.Instance, null, new object[] { list }, CultureInfo.InvariantCulture, null);
  17.  
  18.     if (spCalendarEmailHandler != null)
  19.     {
  20.         MethodInfo mi_ProcessMessage = spCalendarEmailHandlerType.GetMethod("ProcessMessage",
  21.                     BindingFlags.Public | BindingFlags.Instance, null,
  22.                     new Type[] { typeof(SPEmailMessage) }, null
  23.                     );
  24.         if (mi_ProcessMessage != null)
  25.         {
  26.             // result of type SPEmailHandlerResult is ignored
  27.             mi_ProcessMessage.Invoke(spCalendarEmailHandler, new Object[] { emailMessage });
  28.         }
  29.     }
  30.  
  31.     Trace.TraceInformation("SPCalendarEmailHandler processing finished");
  32. }

Using these helper methods our EmailReceived method looks like these:

  1. public override void EmailReceived(SPList list, SPEmailMessage emailMessage, string receiverData)
  2. {
  3.     try
  4.     {
  5.         Trace.TraceInformation("EmailReceived started");
  6.  
  7.         string uid = GetCalendarProp(emailMessage, "UID");
  8.  
  9.         ProcessMessage(list, emailMessage);
  10.  
  11.         string emailTo = emailMessage.Headers["To"];
  12.         SPFieldUserValueCollection users = GetUsersByMailTo(list.ParentWeb, emailTo);
  13.  
  14.         if (!string.IsNullOrEmpty(uid))
  15.         {
  16.             SPListItemCollection existingItems = GetExistingItems(list, uid);
  17.             foreach (SPListItem listItem in existingItems)
  18.             {
  19.                 Trace.TraceInformation("Updating item ID: {0}, To: {1}", listItem.ID, emailTo);
  20.                 listItem[SPBuiltInFieldId.ParticipantsPicker] = users;
  21.                 listItem.Update();
  22.             }
  23.         }
  24.  
  25.         Trace.TraceInformation("EmailReceived calling base handler(s)…");
  26.     }
  27.     catch (Exception ex)
  28.     {
  29.         Trace.TraceInformation("EmailReceived exception: {0}", ex.Message);
  30.         Trace.TraceInformation(ex.StackTrace);
  31.     }
  32.     base.EmailReceived(list, emailMessage, receiverData);
  33. }

Finally, this method seems to fulfill our goals and resolves attendees both on new meeting requests and event updates.

Advertisements

Leave a Comment »

No comments yet.

RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Blog at WordPress.com.

%d bloggers like this: