Accessing email properties in Exchange web server managed API - c#

I'm a complete newbie to EWS, but am trying to convert a happily functioning IMAP program into EWS & am having problems accessing simple fields in the managed API, e.g. From, Sender, BodyType. Can anyone spot what I am doing wrong? Many thanks folks.
ItemView view = new ItemView(99);
SearchFilter.Exists filter = new SearchFilter.Exists(EmailMessageSchema.Id);
FindItemsResults<Item> inboxMessageList = service.FindItems(WellKnownFolderName.Inbox, view);
Console.WriteLine("Inbox message count: " + inboxMessageList.TotalCount);
int messageCounter = 1;
//message loop
foreach (Item thisMessage in inboxMessageList)
{
//Collect info about current email message
Item thisItem = Item.Bind(service, thisMessage.Id);
Console.WriteLine("Current message ID: " + thisMessage.Id);
string uniqueID = "EMAIL-" + DateTime.UtcNow.ToString("yyyyMMdd-HHmmss-fff");
string messageTo = thisItem.DisplayTo;
string messageCC = thisItem.DisplayCc;
string messageFrom = //cant get this to work
string messageSubject = thisItem.Subject;
string messageDate = thisMessage.DateTimeReceived.ToString();
int noOfAttachments = 0;
Boolean messageHasAttachments = thisMessage.HasAttachments;
if (messageHasAttachments) noOfAttachments = thisMessage.Attachments.Count();
string isBodyHtml = //cant seem to implement this either
Boolean domainblacklistResult = fn.CheckIfDomainBlacklisted(messageFrom);
Boolean emailblacklistResult = fn.CheckIfEmailBlacklisted(messageFrom);

To access information about the email message, you need to bind it as an EmailMessage, instead of as an Item. Example:
EmailMessage message = EmailMessage.Bind(service, thisMessage.Id);

Related

Generate unique email in c# for Microsoft Identity Manager

I have a DB ad Microsoft Identity Manager to generate user accounts from HR to MS Active Directory and so on.
I have a such code for generate unique email:
case "mailgenerate":
if (mventry["email"].IsPresent)
{
// Do nothing, the mail was already generated.
}
{
if (csentry["FIRST"].IsPresent && csentry["LAST"].IsPresent);
{
string FirstName = replaceRUEN(csentry["FIRST"].Value);
string LastName = replaceRUEN(csentry["LAST"].Value);
string email = FirstName + "." + LastName + "#test.domain.com";
string newmail = GetCheckedMail(email, mventry);
if (newmail.Equals(""))
{
throw new TerminateRunException("A unique mail could not be found");
}
mventry["email"].Value = newmail;
}
}
break;
//Generate mail Name method
string GetCheckedMail(string email, MVEntry mventry)
{
MVEntry[] findResultList = null;
string checkedmailName = email;
for (int nameSuffix = 1; nameSuffix < 100; nameSuffix++)
{
//added ; and if corrected
findResultList = Utils.FindMVEntries("email", checkedmailName,1);
if (findResultList.Length == 0)
{
// The current mailName is not in use.
return (checkedmailName);
}
MVEntry mvEntryFound = findResultList[0];
if (mvEntryFound.Equals(mventry))
{
return (checkedmailName);
}
// If the passed email is already in use, then add an integer value
// then verify if the new value exists. Repeat until a unique email is checked
checkedmailName = checkedmailName + nameSuffix.ToString();
}
// Return an empty string if no unique mailnickName could be created.
return "";
}
Problem:
When I run sync cycle for first time I get normal email like
duplicateuser1#test.domain.com
For next sync cycle this emails are updated to
duplicateuser#test.domain.com1
This code I'm also using to generate mailnickname and accountname without any problems.
Can anybody say why it is happens?
Thanks!
The problem is the line:
checkedmailName = checkedmailName + nameSuffix.ToString();
checkedmailName has a value like this: firstName.lastName#test.domain.com
So, you're doing this:
checkedmailName = firstName.lastName#test.domain.com + 1;
You need to do something like this:
checkedmailName = checkedmailName.Split('#')[0] + nameSuffix.ToString()+ "#" + checkedmailName.Split('#')[1];
Whith this, you're getting the part before #, adding a int value and then, appending the #+ domain.
Updated by author of thread I changed split -> Split and it works. Thanks!

C# EWS Managed API 2.0 Synchronice Global Address List to application

Hello i try to write an application for a club that makes it easier for older member to use outlook and to send emails. Just a friendly way so elderly People can easy write and see the stuff on screen. But i am a novice programmer and never used the EWS managed API before. What i want is to Synchronice the Global Address List to my programm so i can assign them to an object and do more stuff. But i dont have any clues anymore.
What i tried:
For my own local Contact List (works)
private void AsignValuetoClass(object sender, RoutedEventArgs e)
{
//For the connection
es.UseDefaultCredentials = true;
es.AutodiscoverUrl("max.mustermann#muster.at", RedirectionUrlValidationCallback);
//How many Contacts are in the folder
ContactsFolder contactsfolder = ContactsFolder.Bind(es, WellKnownFolderName.Contacts);
//To get a specific number of contacts
int numItems = contactsfolder.TotalCount < 50 ? contactsfolder.TotalCount : 50;
//object of the Itemview
ItemView view = new ItemView(numItems);
//return the stuff
FindItemsResults<Item> contactIds = es.FindItems(WellKnownFolderName.Contacts, view);
//loop throug the item
foreach (Item item in contactIds)
{
if (item is Contact)
{
//assign of the contact items
Contact contact = item as Contact;
//new list
List<Contact> testlist = new List<Contact>();
//Add the contacts
testlist.Add(contact);
//loop through contact list
foreach (Contact Liste in testlist)
{
//new object on every run
TestKlasse test = new TestKlasse();
//assign
test.id = Convert.ToString(contact.Id);
test.Vorname = contact.GivenName;
test.Nachname = contact.Surname;
}
Console.WriteLine("Some stupid Text");
}
}
}
To get the contacts from the GAL (dont work).
private void SearchContacts(object sender, EventArgs e)
{
//For the connection
es.UseDefaultCredentials = true;
es.AutodiscoverUrl("max.mustermann#muster.at", RedirectionUrlValidationCallback);
NameResolutionCollection nameResolutions = es.ResolveName(
"Contacts",
ResolveNameSearchLocation.DirectoryThenContacts,
true);
foreach (NameResolution nameResolution in nameResolutions)
{
ExpandGroupResults groupResults = es.ExpandGroup(nameResolution.Mailbox.Address);
foreach (EmailAddress member in groupResults.Members)
{
Console.WriteLine(member.Name + " <" + member.Address + ">");
}
}
}
I tried also the resolvename() stuff but its only for one contact or matching contacts. I need every Contact. Here is the code:
private void SearchContacts(object sender, EventArgs e)
{
//For the connection
es.UseDefaultCredentials = true;
es.AutodiscoverUrl("max.mustermann#muster.at", RedirectionUrlValidationCallback);
// Identify the mailbox folders to search for potential name resolution matches.
List<FolderId> folders = new List<FolderId>() { new FolderId(WellKnownFolderName.Contacts) };
// Search for all contact entries in the default mailbox contacts folder and in Active Directory Domain Services (AD DS). This results in a call to EWS.
NameResolutionCollection coll = es.ResolveName("Anderl", folders, ResolveNameSearchLocation.ContactsThenDirectory, false);
foreach (NameResolution nameRes in coll)
{
Console.WriteLine("Contact name: " + nameRes.Mailbox.Name);
Console.WriteLine("Contact e-mail address: " + nameRes.Mailbox.Address);
Console.WriteLine("Mailbox type: " + nameRes.Mailbox.MailboxType);
}
}
Any help would be great so thx for your time. And sorry for my bad english.
This might come a bit late but one way to overcome the 100 user limit would be to simply append each character of the alphabet to "SMTP:" within a loop like this:
private _exchangeSvc = new ExchangeService();
const string SMTP_PREFIX = "SMTP:";
const string ABC = "abcdefghijklmnopqrstuvwxyz";
public List<NameResolution> GetGAL()
{
var gal = new List<NameResolution>();
foreach (char c in ABC)
{
string ambiguousName = SMTP_PREFIX + c;
var nameResCollection = _exchangeSvc.ResolveName(
ambiguousName,
ResolveNameSearchLocation.DirectoryOnly,
false);
gal.AddRange(nameResCollection);
}
//Uncomment the line below if you find duplicates.
// gal = gal.Distict().ToList()
return gal;
}
This worked for me when I needed the GAL via EWS, I only had to retrieve ~400 users though.

C# Outlook relating Inbox and sent items

I am working on a software where i am able to retrieve the inbox and sent items from outlook. What i want to do is to relate the inbox emails with replies (if someone has sent a reply to that email). The list should be displayed in this order
Sender#abc.com Incoming Subject Received Time
sender#abc.com Reply Subject Sent time
What i am planning to do is to retrieve inbox items in one datatable and the sent items in another datatable. It reads the emails one by one on the basis of sender email and the subject, then searches that sender and email in the sent items and if it matches, merge that to a third datatable.
is there any other better way to do so?
Here is the code:
private DataTable GetInboxItems()
{
DataTable inboxTable;
//try
//{
filter = "[ReceivedTime] >= '" + dtpStartDate.Value.ToString("dd/MM/yyyy 12:00 AM") + "' and [ReceivedTime] <= '" + dtpEndDate.Value.ToString("dd/MM/yyyy 11:59 PM") + "'";
Outlook.Application outlookApp = GetApplicationObject();
Outlook.Folder root = outlookApp.Session.DefaultStore.GetRootFolder() as Outlook.Folder;
EnumerateFolders(root);
//string filter = "[ReceivedTime] > '" + dtpStartDate.Value.ToString("dd/MM/yyyy") + "'";
//inbox
Outlook.MAPIFolder inboxFolder = outlookApp.Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox);
inboxTable = CreateTable();
int count = 0;
if (inboxFolder.Items.Count > 0)
{
var restrictedItems = inboxFolder.Items.Restrict(filter);
restrictedItems.Sort("[ReceivedTime]", true); //descending
//foreach (var item in inboxFolder.Items)
foreach (var item in restrictedItems)
{
var mail = item as Outlook.MailItem;
if (mail != null)
{
//try
//{
DataRow row = inboxTable.NewRow();
//row["sn"] = (++count).ToString();
row["sn"] = mail.EntryID + " " + mail.ReceivedByEntryID;
row["MailType"] = "Inbox";
row["SenderName"] = mail.SenderName;
row["SenderEmail"] = mail.SenderEmailAddress;
row["ReceivedDate"] = mail.ReceivedTime;
row["Subject"] = mail.Subject;
row["Body"] = mail.Body != null ? (mail.Body.Length > 25 ? mail.Body.Substring(0, 25) : mail.Body) : null;
//row["Body"] = mail.Body != null ? mail.Body : "";
row["MailSize"] = mail.Size.ToString();
string attachments = null;
if (mail.Attachments.Count > 0)
{
foreach (var attachment in mail.Attachments)
{
if (((Outlook.Attachment)attachment) != null)
//attachments = ((Outlook.Attachment)attachment).FileName + " " + ((Outlook.Attachment)attachment).Size.ToString() + ", ";
attachments += (((Outlook.Attachment)attachment).Size / 1024).ToString() + " KB, ";
}
}
row["AttachmentCount"] = mail.Attachments.Count;
if (attachments != null)
row["AttachmentSize"] = attachments.Substring(0, attachments.Length - 2);
inboxTable.Rows.Add(row);
}
//catch (Exception ex)
//{
// return null;
//}
}
}
return inboxTable;
}
I've made this kind of stuff in an outlook add-in
There is no 100% way to make it ...
The problem is that the conversation ID is not always kept by other software. So you need to use a set of data to link email to their answers:
- Message-ID: this is available in the email headers. Sent items doesn't have this :/
- In-Reply-To: this is also in the email headers
- Topic ID
For the topic ID, I retrieve values in this order (I take the first available):
- MailItem.ConversationIndex: Each reply add bytes to the conversation index
- Reference header
Then, I link email to their reply using topicID, email have the same first X characters than reply. Example original email topic id = abc, reply = abcdef
For all mails than cannot be linked using conversation id, I try to link using Message-ID & In-Reply-To ID
Problem will particularly comes from email sent by outlook (no Message-ID) then user reply without Reference/ConversationIndex header... you'll not have any way to link both mail together.
Hope it helps
EDIT: Here's some code. I've copy/pasted code from different class/method to create a single method, so it may not compile. Take it more as a pseudo-code.
public SimpleTree<MailData> CreateTree(List<MailData> mails)
{
mails.Sort((m1, m2) => m1.TopicId == m2.TopicId ? m2.CreationDate.CompareTo(m1.CreationDate) : m1.TopicId.CompareTo(m2.TopicId));
var tree = new SimpleTree<MailData>();
var i = 0;
while (i < mails.Count)
{
var node = tree.Children.Add(mails[i]);
var topicId = mails[i].TopicId;
var start = i + 1;
while (start < mails.Count
&& !string.IsNullOrEmpty(topicId)
&& !string.IsNullOrEmpty(mails[start].TopicId)
&& mails[start].TopicId.StartsWith(topicId))
{
node.Children.Add(mails[start]);
start++;
}
i = start;
}
// Handle email where TopicId are different, but ParentId is filled with correct value
for (int j = tree.Children.Count - 1; j >= 0; j--)
{
var child = tree.Children[j];
if (child.Children.Count == 0 && !string.IsNullOrEmpty(child.Value.ParentId))
{
var parentNode = tree.FindNode(s => s != null && s.MessageId == child.Value.ParentId);
if (parentNode != null && parentNode != child)
parentNode.Children.Add(child);
}
}
return tree;
}
MailData is a class with the 3 fields needed as explained before:
MessageID (from Message-ID header)
ParentId (from In-Reply-To header)
TopicId (from ConversationIndex or Reference header)
SimpleTree<> is a class to create tree, it's in fact a node with children. Nothing special or related to email here. The .Value property refer to the data associated to the node (MailData here)
The goal is to sort on the TopicId so that we can construct the tree in 1 loop
Then I check all the mail in the tree root to check if we can move them under another mail usine MessageId/ParentId
Just remember that it create a one-level tree, something like:
Mail A
Reply AA
Reply AAA
Mail B
Reply BB
Reply BBB
But you would need something like this:
Mail A
Reply AA
Reply AAA
Mail B
Reply BB
Reply BBB

Exchange EWS get BCC Recipients

I am using EWS to create a StreamingSubscription on an inbox. It is listening for the NewMail event. I am able to pull the From Address, Subject, Body, To Address, CC Address but not the BCC Address. Is there any way to see this list?
CODE:
static void OnEvent(object sender, NotificationEventArgs args)
{
String from = null;
String subject = null;
String body = null;
String to = null;
StreamingSubscription subscription = args.Subscription;
// Loop Through All Item-Related Events
foreach (NotificationEvent notification in args.Events)
{
ItemEvent item = (ItemEvent)notification;
PropertySet propertySet = new PropertySet(ItemSchema.UniqueBody);
propertySet.RequestedBodyType = BodyType.Text;
propertySet.BasePropertySet = BasePropertySet.FirstClassProperties;
// Parse Email
EmailMessage message = EmailMessage.Bind(service, item.ItemId, propertySet);
from = message.From.Address;
subject = message.Subject;
body = message.Body.Text;
if (message.ToRecipients.Count > 0)
{
to = message.ToRecipients[0].Address;
body += "\n TO FIELD";
}
else if (message.CcRecipients.Count > 0)
{
to = message.CcRecipients[0].Address;
body += "\n CC FIELD";
}
/************** Does not work! BccRecipients is always empty *****************/
else if (message.BccRecipients.Count > 0)
{
to = message.BccRecipients[0].Address;
body += "\n BCC FIELD";
}
/************* REST OF CODE ************************/
}
}
That would kind of defeat the point of a blind-carbon-copy. I dont believe it can be done.
Consider using the Journaling feature of Exchange. This uses something called "Envelope Journaling" which includes BCC information for messages within the Exchange environment.
For everything that comes from external sources (gmail) no BCC information is available.
This might help:
http://gsexdev.blogspot.com/2011/06/processing-bccs-in-exchange-transport.html

error using c#mail.dll

I'm trying to read through a gmail account to get gps data that is being sent there ( in the text of a email) from an moble phone (my phone)
using (Pop3Client cl = new Pop3Client())
{
cl.UserName = "crash893";
cl.Password = "password";
cl.ServerName = "pop.gmail.com";
cl.AuthenticateMode = Pop3AuthenticateMode.Pop;
cl.Ssl = true;
cl.Authenticate();
///Get first mail of my mailbox
Pop3Message mg = cl.GetMessage(1); <<<<<<<<<< ERROR
String MyText = mg.BodyText;
///If the message have one attachment
Pop3Content ct = mg.Contents[0];
///you can save it to local disk
ct.DecodeData("c:\\test.txt");
}
but I get a exception on the "get first mail of mailbox message
"Higuchi.Net.Pop3.Pop3ConnectException: Pop3 connection is closed
at Higuchi.Net.Pop3.Pop3Client.SendCommand(String inCommand)
at Higuchi.Net.Pop3.Pop3Client.Execute(String inCommand, Boolean inIsMultiLine)
at Higuchi.Net.Pop3.Pop3Client.Execute(Pop3Command inCommand)
at Higuchi.Net.Pop3.Pop3Client.GetMessage(Int64 inMailIndex)"}
Ideally what i would like to do is open this read all the new unread emails in this account for a certain subject line then read the data in the body and mark them as read
does anyone know why its erroring out
does anyone have any experince with c#mail that hey could point me in the right direction for reading and makring emails as read etc
It is not possible to mark emails as read using the POP protocol.
Try using IMAP.
cl.Port = 995;
using (Pop3Client cl = new Pop3Client())
{
cl.UserName = "ewgsdssw";
cl.Password = "sdgwsegw";
cl.ServerName = "pop.gmail.com";
cl.AuthenticateMode = Pop3AuthenticateMode.Pop;
cl.Port = 995;
cl.Ssl = true;
cl.Authenticate();
///Get first mail of my mailbox
///
int total = Convert.ToInt16(cl.GetTotalMessageCount());
while (total >= 1)
{
Pop3Message mg = cl.GetMessage(total);
if (mg.Subject == "I am Here")
{
// http://maps.google.com/maps?q=38.89552,-77.43265
//(+/- 76 metres.)
string location = mg.BodyText;
location = location.Replace("http://maps.google.com/maps?q=","~");
location = location.Replace("metres.)\r\n\r\n","~");
location = location.Split('~')[1];
location = location.Replace("(+/- ", ",");
location = location.Replace("\r\n", "");
string[] data = location.Split(',');
string lat = data[0];
string lon = data[1];
string res = data[2];
DateTime time = mg.Date;
textBox1.AppendText(string.Format("Lat: {0} LON: {1} Res: {2} TIME: {3}\r\n",lat,lon,res,time.ToString()));
}
total--;
}
}
I do not have experience with C#Mail, and this answer may not help, but I've experienced weirdness in the past while trying to write email send/receive related code.
Turned out the antivirus software we were running at work had a whitelist of allowed .EXE's that could make in/outbound POP3 or SMTP connections. Any chance this is your problem?

Categories

Resources