Second Life of a Hungarian SharePoint Geek

October 15, 2012

How to resolve SharePoint incoming mail alias mapping details?

Filed under: Incoming email, Reflection, SP 2010 — Tags: , , — Peter Holpar @ 20:36

In my recent post I’ve illustrated how to check from code whether a given mail alias is already reserved. If you need to know details about the list / web the alias is mapped to, you have to work further on the issue.

Note: the code below uses non-public API calls and so it is not a supported approach. Use this sample at you own risk and preferably only in test environments.

First I introduced a few extension methods to make our live (and work with Reflection) a bit easier.

  1. public static class Extensions
  2. {
  3.     public static object GetPublicInstanceFieldValue(this Type type, string fieldName, object instance)
  4.     {
  5.         object result = null;
  6.         FieldInfo fi = type.GetField(fieldName);
  7.  
  8.         if ((fi != null) && (instance != null))
  9.         {
  10.             result = fi.GetValue(instance);
  11.         }
  12.  
  13.         return result;
  14.     }
  15.  
  16.     public static void SetPublicInstanceFieldValue(this Type type, string fieldName, object fieldValue, object instance)
  17.     {
  18.         FieldInfo fi = type.GetField(fieldName);
  19.  
  20.         if ((fi != null) && (instance != null))
  21.         {
  22.             fi.SetValue(instance, fieldValue);
  23.         }
  24.     }
  25.  
  26.     public static object GetPublicInstancePropertyValue(this Type type, string fieldName, object instance)
  27.     {
  28.         object result = null;
  29.         System.Reflection.PropertyInfo pi = type.GetProperty(fieldName);
  30.  
  31.         if ((pi != null) && (instance != null))
  32.         {
  33.             result = pi.GetValue(instance, null);
  34.         }
  35.  
  36.         return result;
  37.     }
  38. }

Next, I defined the following wrapper struct for the internal EmailAliasRecord struct (Microsoft.SharePoint.Administration namespace, Microsoft.SharePoint assembly):

  1. public struct EmailAliasRecord
  2. {
  3.     public string Alias { get; private set; }
  4.     public Guid ListId { get; private set; }
  5.     public Guid WebId { get; private set; }
  6.     public Guid SiteId { get; private set; }
  7.     public bool IsValid { get; private set; }
  8.  
  9.     private const string _emailAliasRecordTypeName = "Microsoft.SharePoint.Administration.EmailAliasRecord";
  10.  
  11.     public EmailAliasRecord(object emailAliasRecord) : this()
  12.     {
  13.         InitFields(emailAliasRecord);
  14.     }
  15.  
  16.     private void InitFields(object emailAliasRecord)
  17.     {
  18.         // hack to get the Microsoft.SharPoint assembly
  19.         Assembly sharePointAssembly = typeof(SPWeb).Assembly;
  20.         // and a reference to the type of the EmailAliasRecord internal struct
  21.         Type emailAliasRecordType = sharePointAssembly.GetType(_emailAliasRecordTypeName);
  22.  
  23.         this.Alias = emailAliasRecordType.GetPublicInstanceFieldValue("alias", emailAliasRecord) as string;
  24.         this.ListId = (Guid)emailAliasRecordType.GetPublicInstanceFieldValue("listId", emailAliasRecord);
  25.         this.WebId = (Guid)emailAliasRecordType.GetPublicInstanceFieldValue("webId", emailAliasRecord);
  26.         this.SiteId = (Guid)emailAliasRecordType.GetPublicInstanceFieldValue("siteId", emailAliasRecord);
  27.         this.IsValid = (bool)emailAliasRecordType.GetPublicInstancePropertyValue("IsValid", emailAliasRecord);
  28.     }
  29.  
  30.     public EmailAliasRecord(SqlDataReader reader) : this()
  31.     {
  32.         object emailAliasRecord = null;
  33.  
  34.         // hack to get the Microsoft.SharPoint assembly
  35.         Assembly sharePointAssembly = typeof(SPWeb).Assembly;
  36.         // and a reference to the type of the EmailAliasRecord internal struct
  37.         Type emailAliasRecordType = sharePointAssembly.GetType(_emailAliasRecordTypeName);
  38.  
  39.         emailAliasRecord = sharePointAssembly.CreateInstance(_emailAliasRecordTypeName);
  40.  
  41.         if (emailAliasRecord != null)
  42.         {
  43.             emailAliasRecordType.SetPublicInstanceFieldValue("alias", reader.GetString(0), emailAliasRecord);
  44.             emailAliasRecordType.SetPublicInstanceFieldValue("siteId", reader.GetGuid(1), emailAliasRecord);
  45.             emailAliasRecordType.SetPublicInstanceFieldValue("webId", reader.GetGuid(2), emailAliasRecord);
  46.             emailAliasRecordType.SetPublicInstanceFieldValue("listId", reader.GetGuid(3), emailAliasRecord);
  47.  
  48.             InitFields(emailAliasRecord);
  49.         }
  50.     }
  51.  
  52.     public override string ToString()
  53.     {
  54.         StringBuilder sb = new StringBuilder();
  55.  
  56.         using (SPSite site = new SPSite(this.SiteId))
  57.         {
  58.             using (SPWeb web = site.OpenWeb(this.WebId))
  59.             {
  60.                 SPList list = web.Lists[this.ListId];
  61.  
  62.                 sb.AppendFormat("{0} e-mail alias '{1}' found\r\n", this.IsValid ? "Valid" : "Invalid", this.Alias);
  63.  
  64.                 if (this.IsValid)
  65.                 {
  66.                     sb.Append("Mapped to:'\r\n");
  67.                     sb.AppendFormat("  Web title: {0}\r\n", web.Title);
  68.                     sb.AppendFormat("  Web URL: {0}\r\n", web.Url);
  69.                     sb.AppendFormat("  List title: {0}\r\n", list.Title);
  70.                 }
  71.             }
  72.         }
  73.  
  74.         return sb.ToString();
  75.     }
  76.     
  77. }

Using the code above, it is rather straightforward to call the private GetEmailAliasRecordFromDatabase method of the internal SPEmailMap class (namespace and assembly as above):

  1. private void GetEmailAliasRecordFromDatabase(string mailAlias)
  2. {
  3.     bool found = false;
  4.  
  5.     string spEmailMapTypeName = "Microsoft.SharePoint.Administration.SPEmailMap";
  6.     // hack to get the Microsoft.SharPoint assembly
  7.     Assembly sharePointAssembly = typeof(SPWeb).Assembly;
  8.     // and a reference to the type of the SPElementProvider internal class
  9.     Type spEmailMapType = sharePointAssembly.GetType(spEmailMapTypeName);
  10.  
  11.  
  12.     // spEmailMap will be of type internal class
  13.     // Microsoft.SharePoint.Administration.SPEmailMap
  14.     // defined in Microsoft.SharePoint assembly
  15.     object spEmailMap = sharePointAssembly.CreateInstance(spEmailMapTypeName, false,
  16.         BindingFlags.Public | BindingFlags.Instance, null, null, CultureInfo.InvariantCulture, null);
  17.  
  18.     if (spEmailMap != null)
  19.     {
  20.         // we call
  21.         // internal EmailAliasRecord GetEmailAliasRecordFromDatabase(string alias)
  22.         MethodInfo mi_GetEmailAliasRecordFromDatabase = spEmailMapType.GetMethod("GetEmailAliasRecordFromDatabase",
  23.                 BindingFlags.NonPublic | BindingFlags.Instance, null,
  24.                 new Type[] { typeof(string) }, null
  25.                 );
  26.         if (mi_GetEmailAliasRecordFromDatabase != null)
  27.         {
  28.             object result = mi_GetEmailAliasRecordFromDatabase.Invoke(spEmailMap,
  29.                 new Object[] { mailAlias });
  30.  
  31.             EmailAliasRecord ear = new EmailAliasRecord(result);
  32.  
  33.             if (ear.IsValid)
  34.             {
  35.                 found = true;
  36.                 Console.WriteLine(ear.ToString());
  37.             }
  38.         }
  39.     }
  40.  
  41.     if (!found)
  42.     {
  43.         Console.WriteLine("Found no valid mapping for e-mail alias '{0}'", mailAlias);
  44.     }
  45. }

This code will output the Title property of the associated SPWeb and SPList objects, as well as the Url property of the SPWeb, thus helping you to find out where you set the specified mail alias.

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: