Retrieving email address from a globalAddressList in outlook - c#

Based on the description for the AddressEntry.Address Property, I expect the following to "return a String (string in C#) representing the e-mail address of the AddressEntry."
Outlook.AddressList gal = Application.Session.GetGlobalAddressList();
Outlook.AddressEntries ae = gal.AddressEntries;
List<string> email = new List<string>();
foreach (Outlook.AddressEntry e in ae)
{
email.Add(e.Address);
}
Rather, the email list fills up with strings that look like...
"/o=companyName/ou=Exchange Administrative Group (FYDIBOHF23SPDLT)/cn=Recipients/cn=firstname.lastname"
I would prefer it return something like....
firstname.lastname#mycompany.com
How am I using this incorrectly?

If AddressEntry.Type == "EX", use AddressEntry.GetExchangeUser().PrimarySmtpAddress. Be prepared to handle nulls and exceptions.

Related

validating multiple occurence of e-mails in string in most efficient way

I have string coming in this format as shown bellow:
"mark345345#test.com;rtereter#something.com;terst#gmail.com;fault#mail"
What would be the most efficient way to validate each of these above and fail if it is not valid e-mail?
you can use EmailAddressAttribute class of System.ComponentModel.DataAnnotations namespace for validating the email address. Before that you need to split up individual mails and check whether it is valid or not. the following code will help you to collect the valid mails and invalid mails seperately.
List<string> inputMails = "mark345345#test.com;rtereter#something.com;terst#gmail.com;fault#mail".Split(';').ToList();
List<string> validMails = new List<string>();
List<string> inValidMails = new List<string>();
var validator = new EmailAddressAttribute();
foreach (var mail in inputMails)
{
if (validator.IsValid(mail))
{
validMails.Add(mail);
}
else
{
inValidMails.Add(mail);
}
}
You can use Regex or you might split the string by ';' and try to create a System.Net.Mail.MailAddress instance for each and every address. FormatException will occur if address is not in a recognized format.
If you're sure, that all e-mails are semi colon separated, you can split it and make a list of all. The best way for me to validate each e-mail is to use a regex pattern. I've used this one:
var emailPattern = #"(?=^.{1,64}#)^[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*#(?=.{1,255}$|.{1,255};)(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])(;(?=.{1,64}#)[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*#(?=.{1,255}$|.{1,255};)(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9]))*$";
var incomingString = "mark345345#test.com;rtereter#something.com;terst#gmail.com;fault#mail";
var emails = incomingString.Split(';').ToList();
foreach (var email in emails)
{
if (new Regex(emailPattern).IsMatch(email))
{
// your logic here
}
}
Since .Net has out of the box ways to validate an email id, I would not use a regex and rely upon .Net. e.g the EmailAddressAttribute from System.ComponentModel.DataAnnotations.
A clean way to use it would be something like:
var emailAddressAttribute = new EmailAddressAttribute();
var groups = yourEmailsString.Split(new [] { ';' }, StringSplitOptions.RemoveEmptyEntries)
.GroupBy(emailAddressAttribute.IsValid);
This will give you 2 groups, the one with the Key == true will be valid email ids
var validEmailIds = groups.Where(group => group.Key)
.SelectMany(group => group);
the one with Key == false will be invalid email ids
var invalidEmailIds = groups.Where(group => !group.Key)
.SelectMany(group => group);
You could also run up a for loop after grouping, according to your needs..

Validate email string after split

I have the following string:
var proc = new SAPayslips();
proc.RuleCustomValue = "document.xml|name#domain.com;name#domain.com;name#domain,co.za";
The first value is the name of a xml document, and the rest are emails I would like to utilize.
I can successfully split them and use them but I have a problem with the validation. I would like to throw an exception if the email address doesn't contain an # char.
// retrieves document name
customValues = _ruleCustomValue.Split('|');
// retrieves emails
emails = customValues[1].Split(';');
if(!customValues[1].Contains("#"))
throw new System.InvalidOperationException("Invalid Email adress,");
It doesn't throw the exception when there is no #
You need to check emails to search in array of emails instead of customValues[1] that is a string. Calling Contains on customValues[1] will return true if it contains only one #.
You need to iterate through array of find if any of array element does not contain # in it.
foreach (var email in emails)
if(!email.Contains("#"))
{
throw new System.InvalidOperationException("Invalid Email adress,");
}
You can also use linq, using Enumerable.Any
if(emails.Any(email=>email.indexOf("#") == -1))
throw new System.InvalidOperationException("Invalid Email adress,");
Checking whether or not there is "#" inside is not the exact solution for determining that it is an email adress, I think you are going to need regex pattern for this,
example;
function isEmail(email) {
var pattern = new RegExp(/^[+a-zA-Z0-9._-]+#[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/i);
return pattern.test(email);
};
check it and throw an exception;
if( !isEmail("e#example.com") ) { *here we go! throw exception!*}
here more information about this; link
I hope it will be helpful.
Firstly, it will only throw this in one location (because you have only specified one location: customValues[1])
Secondly, the item you have specified is actually the second item in the array, as all collections start at 0.
What you may want to do instead is go through a loop, and check each email string:
foreach (string s in customValues)
{
if (!s.Contains("#"))
// throw exception
else
// do stuff...
}
You are validating that any email contains a #, not that each email contains a #.
You should get each e-mail and validate through that each e-mail NOT for items in customvalues.
You can try this code:
// retrieves document name
string[]customValues = _ruleCustomValue.Split('|');
// retrieves emails
string[] emails = customValues[1].Split(';');
foreach (string email in emails)
{
if (!email.Contains("#"))
{
throw new System.InvalidOperationException("Invalid Email adress,");
}
}
Try this
// retrieves document name
customValues = _ruleCustomValue.Split('|');
// retrieves emails
emails = customValues[1].Split(';');
foreach(var email in emails)
{
if (!EmailValidated(email))
{
throw new System.InvalidOperationException("Invalid Email adress,");
}
}
private static bool EmailValidated(string emailAddress)
{
const string pattern = #"^(([\w-]+\.)+[\w-]+|([a-zA-Z]{1}|[\w-]{2,}))#"
+ #"((([0-1]?[0-9]{1,2}|25[0-5]|2[0-4][0-9])\.([0-1]?
[0-9]{1,2}|25[0-5]|2[0-4][0-9])\."
+ #"([0-1]?[0-9]{1,2}|25[0-5]|2[0-4][0-9])\.([0-1]?
[0-9]{1,2}|25[0-5]|2[0-4][0-9])){1}|"
+ #"([a-zA-Z]+[\w-]+\.)+[a-zA-Z]{2,4})$";
var match = Regex.Match(emailAddress.Trim(), pattern, RegexOptions.IgnoreCase);
return match.Success;
}

Sort email list by domain

i wanna actuelly sort a list with email addresses by their domain.
Lets say for an example:
var list = new List<string>();
list.Add(a#hotmail.com);
list.Add(b#aon.at);
list.Add(c#gmail.com);
so the result should be:
b#aon.at
c#gmail.com
a#hotmail.com
is that possible without splitting the email addresses ?
Try this:
var sorted = list.OrderBy(x=>new MailAddress(x).Host).ToList();
it will sort your email addresses by mail host
You could use linq for this. However it is absolutely necessary that you split the email address:
list.OrderBy(email => email.Split('#')[1]).ToList();
You can use Regex to get domain of the emails:
var listSorted = list.OrderBy(email => Regex.Match(email, "#.*").Value)
.ToList();
because:
var temp = Regex.Match("a#hotmail.com", "#.*").Value;
tells: take everything after # sign (including # sign) so temp will be #hotmail.com in this case.

How can I check if a string contains an array of values?

I have an array of valid e-mail address domains. Given an e-mail address, I want to see if its domain is valid
string[] validDomains = { "#test1.com", "#test2.com", "#test3.com" };
string email = "test#test1.com"
Is there a way to check if email contains any of the values of validDomains without using a loop?
I would like to recommend you the following code:
HashSet<string> validDomains = new HashSet<string>
{
"test1.com", "test2.com", "test3.com"
};
const string email = "test#test1.com";
MailAddress mailAddress = new MailAddress(email);
if (validDomains.Contains(mailAddress.Host))
{
// Contains!
}
HashSet.Contains Method is an O(1) operation; while array - O(n). So HashSet<T>.Contains is extremely fast. Also, HashSet does not store the duplicate values and there is no point to store them in your case.
MailAddress Class represents the address of an electronic mail sender or recipient. It contains mail address parsing logic (just not to reinvent the wheel).
If you want to be efficient, not only should you avoid using a loop, but you should construct a HashSet for your allowed domains, which would allow O(1) lookup:
string[] validDomains = { "#test1.com", "#test2.com", "#test3.com" };
HashSet<string> validDomainsHashSet = new HashSet<string>(validDomains);
string email = "test#test1.com";
string domain = email.Substring(email.IndexOf('#'));
bool isValidDomain = validDomainsHashSet.Contains(domain);
It would also make sense to exclude the # character from your domains, since it would be present in all and thereby redundant:
string[] validDomains = { "test1.com", "test2.com", "test3.com" };
HashSet<string> validDomainsHashSet = new HashSet<string>(validDomains);
string email = "test#test1.com";
string domain = email.Substring(email.IndexOf('#') + 1);
bool isValidDomain = validDomainsHashSet.Contains(domain);
The simplest way with LINQ (this also ignores the case):
bool validEmail = validDomains
.Any(d => email.EndsWith(d, StringComparer.OrdinalIgnoreCase));
int index = email.IndexOf("#");
var domain = email.Substring(index)
return validDomains.Any(x=>x == domain);
Check this out:
string[] validDomains = { "#test1.com", "#test2.com", "#test3.com" };
string email = "test#test1.com";
if (validDomains.Contains(email.Substring(email.IndexOf("#"))))
{
}
With a for each loop in this way :
string[] validDomains = { "#test1.com", "#test2.com", "#test3.com" };
string email = "test#test1.com";
foreach (string x in validDomains)
{
if (email.Contains(x))
{
// Do Something
}
}
Without a loop in this way(with LINQ) :
if(validDomains.Any(s => email.Contains(s))) {
//Do Something
}
validDomains.Any(validDomain => email.EndsWith(validDomain))
Refer to the documentation of IEnumerable.Any for more details.

How to filter off of a country code?

Okay, here's what I'm attempting.
I have a drop down list with all of the countries in the world.
The user selects one, and that value is passed to a case statement,
if it matches the case, an email is sent.
I only have four different recipents, but I can have upwards to dozens
of countries to match with each one of the four emails. For example:
switch (selectedCountry)
{
case "ca":
sendTo = canadaEmail;
break;
case "uk":
case "de":
case "fr"
sendTo = europeanEmail;
break;
case "bb":
sendTo = barbadosEmail;
break;
default:
sendTo = usEmail;
break;
}
What I would like to know is, what's a better way of doing this rather than having
one huge case statement?
You can use a dictionary instead:
Dictionary<string, string> sendToEmails = new Dictionary<string, string>();
sendToEmails["bb"] = barbadosEmail;
sendToEmails["ca"] = canadaEmail;
sendToEmails["uk"] = europeanEmail;
sendToEmails["de"] = europeanEmail;
Then use TryGetValue to get the value when you need it:
string sendTo;
if (sendToEmails.TryGetValue(selectedCountry, out sendTo))
{
// Send the email here.
}
One advantage of this method is that your dictionary doesn't have to be hard coded into your program. It could just as easily come from a configuration file or a database.
If you choose the database route you could also consider using LINQ:
string sendTo = dc.CountryEmails
.SingleOrDefault(c => c.Country == selectedCountry);
You can't get around the fact that somewhere, somehow, you'll have to enumerate the countries and assign them to an email address. You could do that in any number of ways, be it a database, an external XML file, or an internal List object.
For example:
List<string> europeanEmailCountries = new List<string>();
europeanEmailCountries.AddRange("fr", "de"); // etc
...
if(europeanEmailCountries.Contains(countryCode))
{
sendTo = europeanEmailAddress;
}
This saves you the convoluted switch statement by allowing you to define a list of countries mapped to a particular email address, without going through each potential entry. I might be inclined to populate the list from an XML file instead of hardcoding the values, though.
A couple options that would eliminate the cases:
Store the mappings in a database and look them up by country code.
Build a map in your code with the country code as the key and the email as the value.
Externalize it (XML, database, whatever you like...) and only implement a "state machine" which chooses the right one.
Yes -- if you have a hard coded list somewhere, consider using a collection of a custom type:
public class MyType
{
public string Code { get; set; }
public string Email { get; set; }
}
Then you could do something like this:
List<MyType> myList = new List<MyType>()
{
new MyType() { Code = "A", Email = "something" },
// etc..
}
string emailAddress = myList.Where(m => m.Code == selectedCountry);
Although, I'd say this is very poor design and I would encourage you to use a rdbms of some sort.

Categories