29

I am trying to get a user's email address in AD without success.

String account = userAccount.Replace(@"Domain\", "");
DirectoryEntry entry = new DirectoryEntry();

try {
    DirectorySearcher search = new DirectorySearcher(entry);

    search.PropertiesToLoad.Add("mail");  // e-mail addressead

    SearchResult result = search.FindOne();
    if (result != null) {
        return result.Properties["mail"][0].ToString();
    } else {
        return "Unknown User";
    }
} catch (Exception ex) {
    return ex.Message;
}

Can anyone see the issue or point in the right direction?

TylerH
  • 20,799
  • 66
  • 75
  • 101
user95440
  • 293
  • 1
  • 3
  • 4

8 Answers8

48

Disclaimer: This code doesn't search for a single exact match, so for domain\j_doe it may return domain\j_doe_from_external_department's email address if such similarly named account also exists. If such behaviour is undesirable, then either use a samAccountName filter intead of an anr one used below or filter the results additionally.

I have used this code successfully (where "account" is the user logon name without the domain (domain\account):

// get a DirectorySearcher object
DirectorySearcher search = new DirectorySearcher(entry);

// specify the search filter
search.Filter = "(&(objectClass=user)(anr=" + account + "))";

// specify which property values to return in the search
search.PropertiesToLoad.Add("givenName");   // first name
search.PropertiesToLoad.Add("sn");          // last name
search.PropertiesToLoad.Add("mail");        // smtp mail address

// perform the search
SearchResult result = search.FindOne();
Eugene Podskal
  • 10,270
  • 5
  • 31
  • 53
Fredrik Mörk
  • 155,851
  • 29
  • 291
  • 343
  • 3
    yep worked for me too. Yes need the calling syntax too... Response.Write(result.Properties["givenName"][0].ToString()); Response.Write("
    "); Response.Write(result.Properties["sn"][0].ToString()); Response.Write("
    "); Response.Write(result.Properties["mail"][0].ToString()); Response.Write("
    "); Response.Write(FindName("gruberj"));
    – user95440 Apr 24 '09 at 14:22
  • 3
    I had to use (&(objectCategory=person)(objectClass=user)(anr=" + account + "))"; As the first result was a computer when I just used objectClass=user – Matt Aug 21 '13 at 08:52
  • Just threw together this gist that worked on our domain: https://gist.github.com/roufamatic/8442829 – roufamatic Jan 15 '14 at 19:31
  • 4
    `anr` in the query above is "ambiguous name resolution" and hence does a fuzzy match. If you want an exact match use `sAMAccountName` instead of `anr` in the code above – Gareth Nov 01 '16 at 15:35
  • You might need this as well: the list of all properties associated with the user in AD https://www.manageengine.com/products/ad-manager/help/csv-import-management/active-directory-ldap-attributes.html – George Apr 02 '19 at 12:44
  • @Fredrik, I have tried the above sample code and working fine in local but it's not working in IIS server when I host/deploy my application to a server – Md Aslam Dec 09 '19 at 13:05
  • @MdAslam I don't have a lot of input for you (this answer is 10 years old and I have not really worked with AD since then). My spontaneous guess is that the account under which your code runs in the IIS server doesn't have permissions to query the AD. – Fredrik Mörk Dec 11 '19 at 09:58
  • @Fredrik, Thank you for your response, I will check the permission area and With the help of this same option can we use for Azure Active Directory search without JWT token? i.e AzureActiveDirectory Instead of Directory Searcher. – Md Aslam Dec 11 '19 at 12:50
27

You guys are working too hard:

// Look up the current user's email address
string eMail =  UserPrincipal.Current.EmailAddress;
TylerH
  • 20,799
  • 66
  • 75
  • 101
SMerrill8
  • 528
  • 4
  • 12
  • 3
    What is `UserPrincipal` ? ***namespace and assembly*** ? – Kiquenet Apr 26 '18 at 13:46
  • 3
    Nice, needed a reference to `System.DirectoryServices.AccountManagement` and didn't need to login as the current already is. – CooPzZ Dec 19 '18 at 00:09
  • 3
    Your post is 8 years later than original answer - but hey I am looking now - so I will take 1 line over 7 ... – Ken Mar 07 '19 at 02:57
  • 3
    The OP didn't ask about finding the email of the current user - and even if they did this assumes that the app is using domain authentication. – William Dec 30 '19 at 19:20
  • It worked on LocalHost and then failed once deployed to IIS! Beware of this issue: https://stackoverflow.com/q/11014406/381082 – DeveloperDan Feb 01 '23 at 15:58
3

You can try the below GetUserEmail method. If You are looking out to find the email address for logged-in user in MVC then call the GetUserEmail() function with User.Identity.Name

using System.DirectoryServices;
using System.Linq;

public string GetUserEmail(string UserId)
    {

        var searcher = new DirectorySearcher("LDAP://" + UserId.Split('\\').First().ToLower())
        {
            Filter = "(&(ObjectClass=person)(sAMAccountName=" + UserId.Split('\\').Last().ToLower() + "))"
        };

        var result = searcher.FindOne();
        if (result == null)
            return string.Empty;

        return result.Properties["mail"][0].ToString();

    }

GetUserEmail(User.Identity.Name) //Get Logged in user email address
Kaarthikeyan
  • 500
  • 5
  • 12
3

What about this

public string GetEmailFromSamAccountName(string samAccountName, string domain="YOURCOMPANY")
{
   using (var principalContext = new PrincipalContext(ContextType.Domain, domain))
   {
      var userPrincipal = UserPrincipal.FindByIdentity(principalContext, samAccountName);
      return userPrincipal.EmailAddress;
   }
}
Muflix
  • 6,192
  • 17
  • 77
  • 153
2

You forgot a filter.

Try adding this before calling FindOne:

search.Filter = String.Format("(sAMAccountName={0})", account);
Jakob Christensen
  • 14,826
  • 2
  • 51
  • 81
  • Values must be escaped before they are put into the filter string (http://tools.ietf.org/html/rfc4515#section-3 ff.) – Tomalak Apr 24 '09 at 12:18
  • I think there's a better way. You can set the search scope to `SearchScope.Base`, in which case the only object that the search could possibly retrieve _is_ the root object you supplied. I'm pretty sure no explicit filtering is needed then. – Jonathan Gilbert Feb 15 '19 at 00:47
1

You need to add references for System.DirectoryServices.AccountManagement and include this same references in your using statement. Now you will have access to the current users login details as listed below include the email address.

string loginname = Environment.UserName;
string firstname = UserPrincipal.Current.GivenName;
string lastname = UserPrincipal.Current.Surname;
string name = UserPrincipal.Current.Name;
string eMail = UserPrincipal.Current.EmailAddress;
A. Lartey
  • 59
  • 2
  • I don't think they were asking about the current user - they wanted to ;lookup a specific user - – William Dec 30 '19 at 19:21
1

Also, where do you pull the username from (stored, user input, current identity)? A username can change (be renamed) easily - the SID/Windows Logon Identity on the other hand does not change - so you would be better off doing filters/searches by SID rather than samaccountname - if possible and/or needed design-wise...

Oskar Duveborn
  • 2,189
  • 16
  • 20
0

update: fredrick nailed it....

Jakob is right. You need to filter your search. You can do all sorts of ands and ors there too if you need to, but I think sAMAccountName is enough. You might want to fire up the ADSI tool (it's in the resource kit I think), which lets you walk AD like the registry. it's great for looking at properties. Then find a user, work out what prop you want (mail in this case) and what it's primary key is - sAMAccountName is a good one, but you may also want to filter on the node type.

I'm on a mac, so I can't check it for you, but each node in AD has a type, and you can add that to your filter. I think it looks like this:

((sAMAccountName=bob) & (type=User))

Again, check that - I know it's not type=user, but something LIKE that.

Malachi
  • 3,205
  • 4
  • 29
  • 46
Nic Wise
  • 8,061
  • 2
  • 31
  • 30