Retrieve emails from a non WellKnownFolder in Outlook - c#

I am pulling all emails from an Outlook Exchange Inbox using Microsoft.Exchange.WebServices and the code below works perfect
ExchangeService service = EmailCredentials();
FindItemsResults<Item> findResults = service.FindItems(WellKnownFolderName.Inbox, new ItemView(CountRec));
foreach (Item i in findResults.Items)
{
countOfEmails++;
}
Now there is a request to pull the emails from another user created folder outside the inbox. Anything I've found uses MAPI or EAGetMail but I need to use the exchange webservices. Is this possible?
**EDIT
thanks to #farbiondriven using his code with a few tweaks I have it working now with
ExchangeService service = EmailCredentials();
// Return only folders that contain items.
SearchFilter searchFilter = new SearchFilter.IsGreaterThan(FolderSchema.TotalCount, 0);
FolderView view = new FolderView(10);
// Unlike FindItem searches, folder searches can be deep traversals.
view.Traversal = FolderTraversal.Deep;
// Send the request to search the mailbox and get the results.
FindFoldersResults findFolderResults = service.FindFolders(WellKnownFolderName.MsgFolderRoot, searchFilter, view);
foreach (Folder folder in findFolderResults.Folders)
{
if (folder.DisplayName == "MyFolder")
{
FindItemsResults<Item> findResults = service.FindItems(folder.Id, new ItemView(CountRec));
foreach (Item i in findResults.Items)
{
countOfEmails++;
}
}
}

I can't test it unfortunately, but can you try this ?
ExchangeService service = EmailCredentials();
// Return only folders that contain items.
SearchFilter searchFilter = new SearchFilter.IsGreaterThan(FolderSchema.TotalCount, 0);
// Unlike FindItem searches, folder searches can be deep traversals.
view.Traversal = FolderTraversal.Deep;
// Send the request to search the mailbox and get the results.
FindFoldersResults findFolderResults = service.FindFolders(WellKnownFolderName.Root, searchFilter, view);
foreach (var folder in findFolderResults.Folders)
{
FindItemsResults<Item> findResults = service.FindItems(folder, new ItemView(CountRec));
foreach (Item i in findResults.Items)
{
countOfEmails++;
}
}

Related

Fetch emails received on certain day from non-Well-known folder in shared inbox, Exchange 2016 EWS in C#

I'm trying to fetch all messages from a user-specified date on an Exchange 2016 server using the EWS managed API in C#.
I authenticate with:
public static void Login(string username, string password)
{
service.UseDefaultCredentials = false;
service.Credentials = new WebCredentials(username, password);
service.AutodiscoverUrl(username, RedirectionUrlValidationCallback);
}
Then select the appropriate inbox with
sharedMailbox = new Mailbox(Properties.Settings.Default.Inbox);
the SMTP address is stored in Settings.settings .
I then find the desired folder using the following (from this thread):
targetFolderId = new FolderId(WellKnownFolderName.Inbox, sharedMailbox);
// set folder view
view.PropertySet = new PropertySet(BasePropertySet.FirstClassProperties);
view.PropertySet.Add(FolderSchema.DisplayName);
view.Traversal = FolderTraversal.Deep;
folderResults = service.FindFolders(WellKnownFolderName.Inbox, view);
foreach(Folder f in folderResults)
{
if(f.DisplayName == "Invoices")
{
targetFolderId = f.Id;
//tried showing a message box here
}
}
And use the following (filter code from here and retrieve details from Exchange server code from here) to get the messages I want:
public static void FetchUnreadMessages(DateTime searchDate)
{
SearchFilter greaterthanfilter = new SearchFilter.IsGreaterThanOrEqualTo(ItemSchema.DateTimeReceived, searchDate);
SearchFilter lessthanfilter = new SearchFilter.IsLessThan(ItemSchema.DateTimeReceived, searchDate.AddDays(1));
SearchFilter dayFilter = new SearchFilter.SearchFilterCollection(LogicalOperator.And, greaterthanfilter, lessthanfilter);
results = service.FindItems(targetFolderId, dayFilter, view);
foreach(var item in results.Items)
{
emails.Add((EmailMessage)item);
}
PropertySet properties = (BasePropertySet.FirstClassProperties);
service.LoadPropertiesForItems(emails, properties);
}
I'm not sure where this is breaking down. I tried showing a message box in the foreach loop that finds the folder with the specified name, and it appears the folder is never found. I know there is a folder with that display name in the shared inbox.
I'm not great at debugging and unfortunately my grasp of the EWS API is pretty shaky. Any suggestions as to what I'm missing are welcome.
I keep everything related to the inbox in a static class so I only have to worry about one instance.
There is some problems with you code first
Then select the appropriate inbox with
sharedMailbox = new Mailbox(Properties.Settings.Default.Inbox);
targetFolderId = new FolderId(WellKnownFolderName.Inbox, sharedMailbox);
Nothing wrong with this code but you probably need to understand what's happening here. This code doesn't make any calls to the server it just setups a FolderId class that you can use in a call to get one of the well known folder.
view.PropertySet = new PropertySet(BasePropertySet.FirstClassProperties);
view.PropertySet.Add(FolderSchema.DisplayName);
view.Traversal = FolderTraversal.Deep;
folderResults = service.FindFolders(WellKnownFolderName.Inbox, view);
This code would just search the Inbox Subfolder of the Mailbox who's credentials you are using. eg
service.Credentials = new WebCredentials(username, password);
If you wanted to Search the SubFolders of the Inbox of the SharedMailbox you would use
view.PropertySet = new PropertySet(BasePropertySet.FirstClassProperties);
view.PropertySet.Add(FolderSchema.DisplayName);
view.Traversal = FolderTraversal.Deep;
folderResults = service.FindFolders(targetFolderId , view);
because you are using the targetFolderId in the FindFolder operations that is telling Exchange to Search the Shared Mailbox rather then the mailbox associated with the credentials you are using.

EWS Managed API: External GUID in mail message?

Is it possible to assign EmailMessage specific GUID/ID, which will be later used for search?
var email = new EmailMessage(_service);
email.ExternalGuid = /*Guid or Identifier*/;
email.Send();
And later I should be able to use it to find if this mail is present:
var isExist = _service.IsExistByExternalGuid(/*Guid or Identifier*/);
Why don't you use the InternetMessageid eg Internet Message ID FROM EWS Managed API Send Email c# this Id will then appear in any tracking logs associated with the Message and you can search for the message at a later date using a SearchFilter eg
ItemView ivew = new ItemView(3);
service.TraceEnabled = true;
ExtendedPropertyDefinition PidTagInternetMessageId = new ExtendedPropertyDefinition(4149, MapiPropertyType.String);
SearchFilter sf = new SearchFilter.IsEqualTo(PidTagInternetMessageId, MessageID);
FindItemsResults<Item> iCol = service.FindItems(WellKnownFolderName.Inbox, sf, ivew);
foreach (Item item in iCol.Items)
{
Console.WriteLine(item.Subject);
}

Exchange Server doesn't support the requested version

I get this error because the FindItemsResult isn't compatible with exchange version I'm using which is 2013.
Exchange Server doesn't support the requested version.
My codes:
SearchFilter sf = new SearchFilter.SearchFilterCollection(LogicalOperator.And, new SearchFilter.IsEqualTo(EmailMessageSchema.IsRead, false));
FindItemsResults<Item> items = service.FindItems(WellKnownFolderName.Inbox, sf, new ItemView(10));
foreach (Item item in items.Items)
{
PropertySet propSet = new PropertySet(BasePropertySet.IdOnly, ItemSchema.TextBody);
EmailMessage email = EmailMessage.Bind(service, item.Id, propSet);
Program.SearchItems(email);
}
I could just change it into Exchange 2010 but I get an error in TextBody since this is only for Exchange 2013 and later versions.
Is there any way to convert the code which can work in Exchange 2013?
You need to show more of the code your using as your question doesn't really make sense. The ItemSchema.TextBody was added in Exchange 2013 so as long you are running Exchange 2013 and you have set the Initial server version correctly it will work (So you are either not running 2013 or you have other issue in the code you haven't show). If your looking for something that will work on both Exchange 2007,2010 and 2013 the I would suggest you use.
String MailboxToAccess = "user#domain.com";
ExchangeService service = new Microsoft.Exchange.WebServices.Data.ExchangeService(ExchangeVersion.Exchange2010_SP1);
SearchFilter sfSearchFilter = new SearchFilter.IsEqualTo(EmailMessageSchema.IsRead,false);
service.Credentials = new NetworkCredential("user#domain.com", "password");
service.AutodiscoverUrl(MailboxToAccess, adAutoDiscoCallBack);
FolderId FolderToAccess = new FolderId(WellKnownFolderName.Inbox, MailboxToAccess);
ItemView ivItemView = new ItemView(10);
FindItemsResults<Item> FindItemResults = service.FindItems(FolderToAccess, sfSearchFilter, ivItemView);
PropertySet ItemPropertySet = new PropertySet(BasePropertySet.IdOnly);
ItemPropertySet.Add(ItemSchema.Body);
ItemPropertySet.RequestedBodyType = BodyType.Text;
if (FindItemResults.Items.Count > 0)
{
service.LoadPropertiesForItems(FindItemResults.Items, ItemPropertySet);
}
foreach (Item item in FindItemResults.Items)
{
Console.WriteLine(item.Body.Text);
}
internal static bool adAutoDiscoCallBack(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;
}
That will return just the Text body and will work on any version of EWS.
Cheers
Glen

Error trying to send mail. Not sending using EWS

I'm connecting fine to the Exchange Server and I'm getting all the unread mails but a new message doesn't want to send
Message Code
var newHTML = html.HTMLCode.Replace("{House}", house.Number)
.Replace("{Token}", token.Number)
.Replace("{contactPerson}",
string.Format("<a href=mailto:{0}>{1}</a>",
contactPerson, contactPerson));
LogError.WriteToFile("Has House and token");
//Send mail with token to user
EmailMessage message = new EmailMessage(emailService);
message.ToRecipients.Add(email.From.Address);
message.Subject = string.Format("Electricity token for: {0}", house.Number);
message.Body = new MessageBody(html.HTMLCode);
LogError.WriteToFile("Trying to send");
message.Send();
I have a try catch around this so in the log file I get "Trying to send" but then a error occurs that reads as
"EmailAddress or ItemId must be included in the request."
From examples seen, the way I construct my message seems sufficient but clearly isn't
This is how I got all my unread emails
SearchFilter sf = new SearchFilter.SearchFilterCollection(LogicalOperator.And, new SearchFilter.IsEqualTo(EmailMessageSchema.IsRead, false));
ItemView view = new ItemView(int.MaxValue);
FindItemsResults<Item> findResults = emailService.FindItems(WellKnownFolderName.Inbox, sf, view);
foreach (EmailMessage email in findResults)
{}
Note that I got them as a "EmailMessage"
But were never able to get the senders email address so that's why it didn't want to send.
and then I found this article: FindItem returns only the first 512 bytes of any streamable property
So then I went to go get that specific email like this. Note that I now get the "Item" from the findResults and with that "Item" I do the following.
SearchFilter sf = new SearchFilter.SearchFilterCollection(LogicalOperator.And, new SearchFilter.IsEqualTo(EmailMessageSchema.IsRead, false));
ItemView view = new ItemView(int.MaxValue);
FindItemsResults<Item> findResults = emailService.FindItems(WellKnownFolderName.Inbox, sf, view);
foreach (Item item in findResults)
{
//Get the email message
EmailMessage email = EmailMessage.Bind(emailService, item.Id,
new PropertySet(BasePropertySet.FirstClassProperties, ItemSchema.Attachments));
if (email != null)
{}
}
Now I could finally send emails

Exchange EWS Managed API 2.0 get by date

Im using EWS Managed API to communicate between my c# project and our Exchange 2010 server.
I use this code to get all mails in the inbox from now and three days back.
var ews = new ExchangeService(ExchangeVersion.Exchange2010_SP1);
ews.Credentials = new NetworkCredential(usr, psw, dmn);
ews.AutodiscoverUrl(url);
PropertySet itempropertyset = new PropertySet(BasePropertySet.FirstClassProperties);
itempropertyset.RequestedBodyType = BodyType.Text;
ItemView view = new ItemView(int.MaxValue);
FindItemsResults<Item> findResults;
view.PropertySet = itempropertyset;
do
{
findResults = ews.FindItems(WellKnownFolderName.Inbox, view);
foreach (Item item in findResults.Items)
{
if (item.DateTimeCreated < DateTime.Now.AddDays(-3)) continue;
item.Load(itempropertyset);
var message = EmailMessage.Bind(ews, item.Id,
new PropertySet(BasePropertySet.FirstClassProperties, ItemSchema.Attachments));
string to = message.ToRecipients[0].Address.ToLower();
string body = item.Body;
}
view.Offset += findResults.TotalCount;
} while (findResults.MoreAvailable);
Now the problem. I want to improve this line if (item.DateTimeCreated < DateTime.Now.AddDays(-3)) continue; because when i use this, the api gets all the messages from inbox and just continue if its older then three days. I want specify this filter earlier in the code, so the api dont have to handle all messages.
If I understand the problem correctly, this should work. You can see all search filters available here: EWS Search Filters
ItemView view = new ItemView(int.MaxValue);
FindItemsResults<Item> findResults;
view.PropertySet = itempropertyset;
SearchFilter searchFilter =
new SearchFilter.IsGreaterThan(ItemSchema.DateTimeReceived, DateTime.Now.AddDays(-3));
findResults = service.FindItems(WellKnownFolderName.Inbox, searchFilter, view);

Categories

Resources