Wednesday, June 11, 2008

Retrieving a user's email address from Active Directory

An application I'm working on requires complete user management through Active Directory. So I'm slowly building up an "ADUtils" support class to wrap up all the necessary AD querying. I've found a decent amount of ADSI examples online, though finding specific information, and extracting best practices from these has been difficult.

Being rather new to AD, I don't make any claims that the code below follows all best practices, though I'll try to explain what I've done and why I've done it that way. If you know of a better way to accomplish the following, please let me know.

    /// <summary>
/// Retrieves the user's email address from AD
/// </summary>
/// <param name="user">User's NT account name without domain prefix</param>
/// <returns>User's email address</returns>
public static string GetEmailAddress(string user) {
DirectoryEntry entry = new DirectoryEntry("LDAP://DC=yourdomain,DC=com");
DirectorySearcher searcher = new DirectorySearcher(entry);

searcher.Filter = String.Format("(SAMAccountName={0})", user);
searcher.PropertiesToLoad.Add("mail");

SearchResult result = searcher.FindOne();

string emailAddress;

try {
emailAddress = result.Properties["mail"][0].ToString();
} catch (ArgumentOutOfRangeException e) {
emailAddress = String.Empty;

//TODO: log/display error
}

return emailAddress;
}

  • The LDAP address does not specify the domain controller. This allows AD to intelligently choose which DC to use.

  • By explicitly stating what properties to load, you save the server from loading them all.

  • "searcher.FindOne()" does exactly what it says and just loads one result. I'm not sure of the performance benefit of using this vs. "searcher.FindAll()" if there's only one result anyway, but this is certainly better form if you're expecting only one result.

  • Lastly, if the field is left blank in AD, you will get an ArgumentOutOfRangeException instead of a blank field back, so it's a good idea to explicitly handle it.

Using my "GetUsersInGroup" method, you can use the "GetEmailAddress" method to get all group members' email addresses:

using System.Configuration;
...
string LDAPGroupAddress = "LDAP://CN=yourgroup,CN=Users,DC=yourdomain,DC=com";
CommaDelimitedStringCollection emailList = new CommaDelimitedStringCollection();

ADUtils.GetUsersInGroup(LDAPGroupAddress).ForEach(delegate(string member) {
emailList.Add(AuthUtils.GetEmailAddress(member));
});
...
mail.To.Add(emailList.ToString());

And since we're on the topic of performance, the generic List method "ForEach" is faster than the equivalent regular "foreach", though "for" is actually the fastest, but there's really not much of a difference at all unless you're dealing with a huge number of iterations.

As a side note, this is my first post using Windows Live Writer, and with the incredibly helpful "Insert Formatted Code" add-in. I'm very impressed with both.

No comments: