Determine if mailbox exists using Exchange Web Services API - c#

Using the Exchange Web Services API, is it possible to determine whether a mailbox/e-mail address such as someone#mydomain.com exists within an organization?
If so, which is the simplest way to do this and is it possible without the use of impersonation?
Case: A Windows Service regularly sends e-mails to people within the organization. It does not have any explicit knowledge about their e-mail adresses. It only knows their username and assumes that their e-mail address is username#mydomain.com. This is true for all users except for a few that do not have mailboxes. In these cases, it should not attempt to send the e-mail in the first place.
Solution:
As suggested by mathieu: look for user and e-mail address in Active Directory instead. This function gets the job done:
using System.DirectoryServices.AccountManagement;
// ...
public static bool TryGetUserEmailAddress(string userName, out string email)
{
using (PrincipalContext domainContext =
new PrincipalContext(ContextType.Domain, Environment.UserDomainName))
using (UserPrincipal user =
UserPrincipal.FindByIdentity(domainContext, userName))
{
if (user != null && !string.IsNullOrWhiteSpace(user.EmailAddress))
{
email = user.EmailAddress;
return true;
}
}
email = null;
return false; // user not found or no e-mail address specified
}

Determining if an user has a mailbox with EWS only could be more complicated than expected, especially without impersonation.
If you're in an Active Directory domain, you should rely on the DirectoryEntry information to determine the mailbox of an user, and send email accordingly. If you got your user login, it's really easy to get the associated DirectoryEntry.

there is an easy way to do it by checking the user availability like the following code.
I tried this and it is working for me.
I am not sure about other cases when availability result returns error but for sure when the email is not right it does
to define your exchange service refer to this: https://learn.microsoft.com/en-us/exchange/client-developer/exchange-web-services/get-started-with-ews-managed-api-client-applications
ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2007_SP1);//You version
service.Credentials = new WebCredentials("user1#contoso.com", "password");
service.AutodiscoverUrl("user1#contoso.com", RedirectionUrlValidationCallback);
string email = "TEST#YOUR.COM";
// Get User Availability after 6 months
AttendeeInfo attendee = new AttendeeInfo(email);
var attnds = new List<AttendeeInfo>();
attnds.Add(attendee);
var freeTime = service.GetUserAvailability(attnds, new
TimeWindow(DateTime.Now.AddMonths(6), DateTime.Now.AddMonths(6).AddDays(1)), AvailabilityData.FreeBusyAndSuggestions);
//if you receive result with error then there is a big possibility that the email is not right
if(freetimes.AttendeesAvailability.OverallResult == ServiceResult.Error)
{
return false;
}
return true;

Related

Validating spam, temporary emails and emails with invalid domains

recently I have noticed a lot of users being registered to my site and they all use disposable emails, temporary email addresses or fake emails to register on the site...
What I have done to partially prevent that is I added mailgun email verification which tells me whether an email is valid or not , disposable one or not...
This filtered out like 95% of the fake emails and users, however there is still a small portion of them which go "unnoticed". What I have figured out to do are following things via code:
public static bool IsValidEmail(string email)
{
RestClient client = new RestClient();
client.BaseUrl = new Uri("https://api.mailgun.net/v3");
client.Authenticator = new HttpBasicAuthenticator("api", "");
RestRequest request = new RestRequest();
request.Resource = "/address/validate";
request.AddParameter("address", email);
var res = new JavaScriptSerializer().Deserialize<RootObject>(client.Execute(request).Content);
if (res.is_disposable_address || res.is_valid==false)
return false;
return true;
}
This is one step via mailgun that I described previously... And second method to prevent spam/fake users is that I have set up manually a table in my DB with blacklisted domains to which registration won't be allowed... And the logic for that is:
public static bool IsValid(string email)
{
using (var ctx = new myEntities())
{
var blacklistedProviders = ctx.BlacklistedDomains.ToList();
foreach (var item in blacklistedProviders)
{
if (email.ToLower().Contains(item.DomainName.ToLower()))
return false;
}
}
return true;
}
However I don't think this will prevent them from doing more malicious stuff on the website...
I have also added google recaptcha to harden the process of registration for spammers, that does the job well too....
So my questions here are:
Are there any other ways that I can validate the email to see whether it is disposable or invalid email
What other way could I implement to prevent users from creating fake accounts?
Can someone help me out with this?

C# Console Application - Parsing Office 365 Inbox

I was able to succeed via a package I found called EAGetMail. Unfortunately, I realized soon after that they have a token system and this is not a free approach.
There are a couple other choices available, like using Outlook Mail REST API, and MimeKit, but I'm lost on how to achieve my end result because no "start to finish" code is available on either of these references that demonstrates how to parse an Inbox for an account.
I've started to write this with the help of Mimekit, but am not sure if this is the proper way at all.
I must imagine it looks something like:
using (var client = new SmtpClient ())
{
client.Connect("outlook.office365.com", 587);
client.Authenticate("myemail#office365account.com", "mypassword");
var message = MimeMessage.Load(stream);
}
I don't know how to setup the stream mentioned above, and I don't know if it's possible to do this with Mimekit and Office 365.
I'm open to seeing a solution for this in any other approach that's not through EAGetMail. If anyone has a lightweight solution ranging from actual establishing a connection, to pulling messages from the inbox, would be great to see!
I've got it using EWS (Exchange Web Services). Here's my code:
private static bool RedirectionUrlValidationCallback(string redirectionUrl)
{
// The default for the validation callback is to reject the URL.
bool result = false;
Uri redirectionUri = new Uri(redirectionUrl);
// Validate the contents of the redirection URL. In this simple validation
// callback, the redirection URL is considered valid if it is using HTTPS
// to encrypt the authentication credentials.
if (redirectionUri.Scheme == "https")
{
result = true;
}
return result;
}
static void Main(string[] args)
{
ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2013_SP1);
service.Credentials = new WebCredentials("email#myemail.com", "myPassword");
service.AutodiscoverUrl("email#myemail.com", RedirectionUrlValidationCallback);
//creates an object that will represent the desired mailbox
Mailbox mb = new Mailbox(#"email#myemail.com");
//creates a folder object that will point to inbox folder
FolderId fid = new FolderId(WellKnownFolderName.Inbox, mb);
//this will bind the mailbox you're looking for using your service instance
Folder inbox = Folder.Bind(service, fid);
//load items from mailbox inbox folder
if (inbox != null)
{
FindItemsResults<Item> items = inbox.FindItems(new ItemView(100));
foreach (var item in items)
{
item.Load();
Console.WriteLine("Subject: " + item.Subject);
}
}
}

Outlook - Find email of account the message was sent to

My client has a problem and it mean I have a problem:
In the case where email recipient have multiple emails configured in Outlook -
I have one yahoo email account and 2 Exchange accounts from different Exchange servers.
When processing incoming email in ProcessItemAdd event handler (Add-In Express)
I try to discover what account out of 3 this email was sent to:
So my first method is:
Outlook.MailItem re = ((Outlook._MailItem)mail).Reply();
if (re != null)
{
var thisEmail = "";
Outlook.Account account = re.SendUsingAccount;
if (account != null)
{
thisEmail = account.SmtpAddress;
Log.VerboseFormat("thisEmail = {0}", thisEmail);
Marshal.ReleaseComObject(re);
re = null;
Marshal.ReleaseComObject(account);
account = null;
It works perfectly on my machine with Outlook 2010 32bit, but does not work on my client machine with Outlook 2010, returning empty string.
So my second (backup method) is:
if (String.IsNullOrEmpty(thisEmail))
{
// This requires that in the case of Exchange account it should be cached Exchange account.
thisEmail = (string)mail.PropertyAccessor.GetProperty("http://schemas.microsoft.com/mapi/id/{00062008-0000-0000-C000-000000000046}/8580001F");
Log.VerboseFormat("Got receiver account email address from schema: {0}", thisEmail);
}
}
}
Again this works perfectly on my machine but does not work on client machine, returning empty string.
I did verify that in my client's case the sender is Exchange account with caching...
BTW, it works fine on client machines when sender is non-Exchange and receiver is Exchange account...
Is there any other method that reliably can determine what account the email was sent to (in case of multiple recipients).
Here is my latest code that works on 2010/2013 but not on 2007. On the latter account is null and x-header returned empty:
Outlook.MailItem re = ((Outlook._MailItem)mail).Reply();
if (re != null)
{
var thisEmail = "";
Outlook.Account account = re.SendUsingAccount;
if (account != null)
{
thisEmail = account.SmtpAddress;
Log.VerboseFormat("thisEmail = {0}", thisEmail);
Marshal.ReleaseComObject(re);
re = null;
Marshal.ReleaseComObject(account);
account = null;
if (String.IsNullOrEmpty(thisEmail))
{
string x_headers = (string)mail.PropertyAccessor.GetProperty("http://schemas.microsoft.com/mapi/proptag/0x007D001F");
thisEmail = FindTargetEmail(x_headers);
Log.Verbose("Extracted target email address from MIME x-headers: {0}", thisEmail);
}
}
else
{
Log.Verbose("account is null...");
if (String.IsNullOrEmpty(thisEmail))
{
string x_headers = (string)mail.PropertyAccessor.GetProperty("http://schemas.microsoft.com/mapi/proptag/0x007D001F");
thisEmail = FindTargetEmail(x_headers);
Log.Verbose("Extracted target email address from MIME x-headers: {0}", thisEmail);
}
}
EDIT:
Well, it is not over yet. Although it works well on all machines that I have client reports a problem on 2010. It is very strange problem.
User user1#domain1.com (cached Exchange account) sends email to user user2#domain2.com (gmail account). When I parse the MIME header on the receiver side with the above code in order to get the address that this email was sent to...I get back user1#domain1.com instead of user2#domain2.com !! How this is possible? I know that I am parsing the right part of the header (do I ?) and on my machines it returns the correct result...why it does not happen on SOME of my client's machines??
Experts, any ideas?
Typically a Store in the Outlook profile represents a separate account. You may handle the ItemAdd event of the Items class (ProcessItemAdd in ADX terms) in each store to identify the account the email message was sent to.

Using the TFS 2012 API, how do I get the email address of a user?

I am trying to get the email address of a particular user in TFS 2012 using the API. I have set the users Preferred Email address in the Profile section. I have done plenty of searching online and have the following code.
var userId = "myUserId";
var collection = new TfsTeamProjectCollection(tfsUri, tfsCerd);
var managementService = collection.GetService<IIdentityManagementService>();
var member =
managementService
.ReadIdentity(
IdentitySearchFactor.AccountName,
userId,
MembershipQuery.Direct,
ReadIdentityOptions.ExtendedProperties);
var emailAddress = member.GetAttribute("Mail", null)
This code is both a success and a failure. It is a success in that it successfully retrieves the specified user; however, the problem is that the Email attribute is blank. When I analyzed the member variable, I noticed the "Mail" attribute was listed there and it was empty. I then noticed there were two other attributes called "ConfirmedNotificationAddress" and "CustomNotificationAddress" that had my preferred email address correctly in there.
I am wondering why I can't seem to get the "Mail" variable to load properly with the preferred email address as I will need this code to work on a lot of peoples servers.
Try using Mail instead of Email for the attribute name - that works for me.
Also, if that doesn't work, check the results of member.GetProperties() - maybe that will give you the right name to use.
For me, GetProperty("Mail") also worked.
I bumped into the same problem, I found a work around by getting my users email address from AD using the following code.
public string GetUserEmail(string username)
{
using (var pctx = new PrincipalContext(ContextType.Domain))
{
using (UserPrincipal up = UserPrincipal.FindByIdentity(pctx, username))
{
return up != null && !string.IsNullOrEmpty(up.EmailAddress) ? up.EmailAddress : string.Empty;
}
}
}
But then I found that it would throw an exception when my user was not in my domain. So this code helped me have an a second source. If I didn't find in AD i would go and use the IdentityManagementService.
public TeamFoundationIdentity GetUserByAccountName(string account)
{
var ims = _tfServer.GetService<IIdentityManagementService>();
return ims.ReadIdentity(IdentitySearchFactor.DisplayName, account, MembershipQuery.Expanded, ReadIdentityOptions.ExtendedProperties);
}
Then I would simply use this execution.
var ownerMail = GetUserEmail(checkinEvent.Resource.CheckedInBy.DisplayName);
if (string.IsNullOrEmpty(ownerMail))
{
ownerMail = GetUserByAccountName(checkinEvent.Resource.CheckedInBy.DisplayName).GetProperty("Mail").ToString();
}

Validating a user's credentials remotely

I currently use LogonUser() to authenticate my user's username and password on my local domain at the office and it works great for what i need it to do.
Since I developed the app I now need to make it work over my VPN. It seems LogonUser() will not work with REMOTELY validating credentials. Or will it? Is it possible to use LogonUser() to validate a user's credentials on a REMOTE domain account?
I have read in some places that using LOGON32_LOGON_NEW_CREDENTIALS for the 4th param (login type) and LOGON32_PROVIDER_WINNT50 for the 5th param (provider) would do the trick. But every time I try that I ALWAYS get success... I can supply a bogas user and pass and it will work every time :(.
Ideas?
Edit - Added Notes
Tried to use this function but I kept getting the exception telling me the user/pass was bad.
public bool Win2kCredentialsIsValid(string domain, string username, string password)
{
string adPath = "LDAP://" + domain + "/rootDSE";
DirectoryEntry adRoot = new DirectoryEntry(adPath, domain + "\\" + username, password, AuthenticationTypes.ReadonlyServer);
try
{
object o = adRoot.Properties["defaultNamingContext"];
}
catch
{
return false;
}
return true;
}
--
Edit - Added More Notes
OK so I tried yet another example just to get it to work and started down this path, and there are a few things to note...
MyServerHostName is exactly that, my server's hostname. EX: 'Server01'.
My domain name in this example is 'MyDomain.local'
So that makes my FQN for the server 'Server01.MyDomain.local'
I tried to make this work and got the following error...
The supplied context type does not match the server contacted. The server type is Domain.
This errored out at : var context = new PrincipalContext(ContextType.ApplicationDirectory, "MyServerHostName:389", "DC=MyDomain,DC=local"))
private bool CheckADCredentials()
{
bool bResults;
using (var context = new PrincipalContext(ContextType.ApplicationDirectory,
"MyServerHostName:389",
"DC=MyDomain,DC=local"))
{
var username = "firstname.lastname";
var email = "firstname.lastname#MyServerHostName";
var password = "123456";
var user = new UserPrincipal(context)
{
Name = username,
EmailAddress = email
};
user.SetPassword(password);
user.Save();
if (context.ValidateCredentials(username, password, ContextOptions.SimpleBind))
{
bResults = true;
}
else
{
bResults = false;
}
user.Dispose();
}
return bResults;
}
I ended up going with a different solution. Instead of trying to validate a user's account on a domain that my PC was not connected to I ended up caching my domain credentials in the database and just built a salted MD5 type encrypt function so it would make it hard .. er.. for someone to crack it. ;)
Now I just validate against cached credentials in the database when working remotely... It just required the user to first login on the domain but then the user can use it remotely day and night. ;)
Thanks!

Categories

Resources