EWS foreach all unread messages does not work - c#

I need to loop through all unread messages in inbox and download first attachment for every email, my code works but only for first email, why ?
/* load all unread emails */
SearchFilter sf = new SearchFilter.SearchFilterCollection(LogicalOperator.And, new SearchFilter.IsEqualTo(EmailMessageSchema.IsRead, false));
FindItemsResults<Item> findResults = service.FindItems(WellKnownFolderName.Inbox, sf, new ItemView(1));
/* loop through emails */
foreach (EmailMessage item in findResults)
{
item.Load();
/* download attachment if any */
if (item.HasAttachments && item.Attachments[0] is FileAttachment)
{
Console.WriteLine(item.Attachments[0].Name);
FileAttachment fileAttachment = item.Attachments[0] as FileAttachment;
/* download attachment to folder */
fileAttachment.Load(downloadDir + fileAttachment.Name);
}
/* mark email as read */
item.IsRead = true;
item.Update(ConflictResolutionMode.AlwaysOverwrite);
}
Console.WriteLine("Done");
in my inbox it set the first email to read but the sript stops then and write "Done." to console window. Whats wrong ?

The problem is that you're only requesting a single item from Exchange.
FindItemsResults<Item> findResults = service.FindItems(
WellKnownFolderName.Inbox,
sf,
new ItemView(1));
The ItemView class constructor takes a page size as its parameter, which is defined as:
The maximum number of items the search operation returns.
So you're requesting a single item, which explains why your foreach completes after that one item.
To test this you can simply increase the pageSize to something more reasonable, like 100 or 1000.
But to fix it you should follow the idiomatic double-loop:
SearchFilter sf = new SearchFilter.SearchFilterCollection(LogicalOperator.And, new SearchFilter.IsEqualTo(EmailMessageSchema.IsRead, false));
FindItemsResults<Item> findResults;
ItemView view = new ItemView(100);
do {
findResults = service.FindItems(WellKnownFolderName.Inbox, sf, view);
foreach (var item in findResults.Items) {
// TODO: process the unread item as you already did
}
view.Offset = findResults.NextPageOffset;
}
while (findResults.MoreAvailable);
Here we continue retrieving more items from Exchange (in batches of 100) as long as it tells us there are more items available.

public void readMail()
{
ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2010);
service.Credentials = new WebCredentials("uname", "password", "domain");
service.Url = new Uri("URL");
System.Net.ServicePointManager.ServerCertificateValidationCallback = ((sender, certificate, chain, sslPolicyErrors) => true);
SearchFilter searchFilter = new SearchFilter.SearchFilterCollection(LogicalOperator.And, new SearchFilter.IsEqualTo(EmailMessageSchema.IsRead, false));
FindItemsResults<Item> findResults = service.FindItems(WellKnownFolderName.Inbox, searchFilter, new ItemView(int.MaxValue));
foreach (EmailMessage item in findResults.Items)
{
item.Load();
if (item.HasAttachments)
{
foreach (var i in item.Attachments)
{
try
{
FileAttachment fileAttachment = i as FileAttachment;
fileAttachment.Load("C:\\Users\\xxxxx\\Desktop\\comstar\\Download\\test\\" + fileAttachment.Name);
}
catch(Exception e)
{
Console.Write(e);
}
}
}
//set mail as read
item.IsRead = true;
item.Update(ConflictResolutionMode.AutoResolve);
}
}

Related

Trying to find unique id of folder in EWS C# API

I am trying to find the unique id of a folder in Outlook.
For some reason I keep getting an error with the AutoDiscoverUrl method, but I have no idea why. I have tried all the possible solutions on StackOverflow.
I am trying to run it in a commandline program using C#, and have commented/documented the code. I have used others' example on how to do this, but it doesn't work.
static void Main(string[] args)
{
// Set server binding
ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2013_SP1);
service.UseDefaultCredentials = true;
// Set Credentials
service.Credentials = new WebCredentials("xxxx", "xxxxx", "xxxx");
service.UseDefaultCredentials = true;
service.Url = new Uri("https://outlook.office365.com/EWS/Exchange.asmx");
// Set the URL
service.AutodiscoverUrl("xxxx", Callback);
// Error Tracing
service.TraceEnabled = true;
// Redirect callback
// Set View
FolderView view = new FolderView(100);
view.PropertySet = new PropertySet(BasePropertySet.IdOnly);
view.PropertySet.Add(FolderSchema.DisplayName);
view.Traversal = FolderTraversal.Deep;
FindFoldersResults findFolderResults = service.FindFolders(WellKnownFolderName.Root, view);
// Find specific folder
foreach (Folder f in findFolderResults)
{
// Show FolderId of the folder "test"
if (f.DisplayName == "test")
{
Console.WriteLine(f.Id);
}
}
}
private static bool Callback(string redirectionUrl)
{
bool result = false;
var redirectionUri = new Uri(redirectionUrl);
if (redirectionUri.Scheme == "https")
{
result = true;
}
return result;
}
You could find the unique id of the folder using the below code:
ExchangeService Service = new ExchangeService(ExchangeVersion.Exchange2013_SP1);
Service.UseDefaultCredentials = false;
Service.Credentials = new WebCredentials("yourUserID", "yourPassword");
Mailbox ProdSupportMailbox = new Mailbox("ProdSupport#company.com");
Service.AutodiscoverUrl("ProdSupport#company.com");
FolderView view = new FolderView(100);
view.PropertySet = new PropertySet(BasePropertySet.IdOnly);
view.PropertySet.Add(FolderSchema.DisplayName);
view.Traversal = FolderTraversal.Deep;
FindFoldersResults findFolderResults = server.FindFolders(WellKnownFolderName.Root, view);
// find specific folder
foreach(Folder f in findFolderResults)
{
// show folderId of the folder "Test"
if (f.DisplayName == "Test")
{
Console.WriteLine(f.Id);
}
}
For more information, please refer to these links:
Exchange Web Service FolderId for a not well known folder name
Microsoft Exchange Web Services reading my local Outlook folders INSTEAD of another address

Using EWS to retrieve emails and want only the text from the body

I am able to retrieve all the emails and log them but I can't seem to get the body to just be plain text. I've tried looking at other examples on here but I can't seem to grasp the problem. Below is my code so far:
//retrieve emails in blocks of 50
int offset = 1;
int pageSize = 50;
bool moreEmails = true;
ItemView view = new ItemView(pageSize, offset, OffsetBasePoint.Beginning);
view.PropertySet = PropertySet.IdOnly;
while (moreEmails)
{
findResults = service.FindItems(WellKnownFolderName.Inbox, view);
foreach (var item in findResults.Items)
{
emails.Add((EmailMessage)item);
}
moreEmails = findResults.MoreAvailable;
if (moreEmails)
{
view.Offset += pageSize;
}
}
PropertySet properties = new
PropertySet (BasePropertySet.FirstClassProperties);
service.LoadPropertiesForItems(emails, properties);
properties.RequestedBodyType = BodyType.Text;
I'm initialising the variables in a separate function:
private static void CheckRules()
{
try
{
foreach (var EmailParam in emails)
{
FromEmail = EmailParam.From.Address.ToString();
EmailDate = EmailParam.DateTimeReceived.ToString("yyyy-MM-dd hh:mm:ss");
EmailSubject = EmailParam.Subject.ToString();
EmailBody = EmailParam.Body.Text.ToString();
etc...
So again, I just want the body to be plain text. Thanks in advance for any help!

Get emails from custom and sent mail folders in c# using Exchange Web Services

I'm trying to retrieve emails from multiple folders including Inbox, Sent, and some custom folders. I'm first filtering the folders so I can loop over them, calling FindItems to return their contents. The code below works without searchFilter4 (line 10), but with it I get this unhelpful error:
'Microsoft.Exchange.WebServices.Data.ServiceResponseException' in Microsoft.Exchange.WebServices.dll
My code:
// Folder name filter for Inbox, Completed, Inprogress, and Sent folders:
SearchFilter searchFilter1 = new SearchFilter.IsEqualTo(FolderSchema.DisplayName, "Inbox");
SearchFilter searchFilter2 = new SearchFilter.IsEqualTo(FolderSchema.DisplayName, "Completed");
SearchFilter searchFilter3 = new SearchFilter.IsEqualTo(FolderSchema.DisplayName, "In Progress");
SearchFilter searchFilter4 = new SearchFilter.IsEqualTo(, WellKnownFolderName.SentItems);
SearchFilter.SearchFilterCollection searchFilterCollection = new SearchFilter.SearchFilterCollection(LogicalOperator.Or);
searchFilterCollection.Add(searchFilter1);
searchFilterCollection.Add(searchFilter2);
searchFilterCollection.Add(searchFilter3);
searchFilterCollection.Add(searchFilter4);
// Find folders:
FindFoldersResults findResults = service.FindFolders(
WellKnownFolderName.MsgFolderRoot, searchFilterCollection,
new FolderView(int.MaxValue) { Traversal = FolderTraversal.Deep }
);
I figured it out while writing my question...
All I needed to do was add the folder to my findeResults after calling FindFolders with this line:
findResults.Folders.Add(Folder.Bind(service, WellKnownFolderName.SentItems));
My new code:
// Folder name filter for Inbox, Completed, Inprogress, and Sent folders:
SearchFilter searchFilter1 = new SearchFilter.IsEqualTo(FolderSchema.DisplayName, "Inbox");
SearchFilter searchFilter2 = new SearchFilter.IsEqualTo(FolderSchema.DisplayName, "Completed");
SearchFilter searchFilter3 = new SearchFilter.IsEqualTo(FolderSchema.DisplayName, "In Progress");
SearchFilter.SearchFilterCollection searchFilterCollection = new SearchFilter.SearchFilterCollection(LogicalOperator.Or);
searchFilterCollection.Add(searchFilter1);
searchFilterCollection.Add(searchFilter2);
searchFilterCollection.Add(searchFilter3);
// Find folders:
FindFoldersResults findResults = service.FindFolders(
WellKnownFolderName.MsgFolderRoot, searchFilterCollection,
new FolderView(int.MaxValue) { Traversal = FolderTraversal.Deep }
);
// Add SentItems to the findResults:
findResults.Folders.Add(Folder.Bind(service, WellKnownFolderName.SentItems));

Execute mail reader program without visual studio

With reference to my previous question, I already wrote my program and it is working awesome when I am using VS2008 for run it.
I have two more questions:
1. I want to check with you guys when I run my program all the mail are appearing in VS output as xml file, but I never used to print them in output. is it usual for all or I need to add something to remove it. I feel it takes long time from my PC to show mails in output.
2. my second question is that when I want to use only exe file stand alone(run program via exe file not with VS ) I am receiving below error and program is hanging & close.
"MailReader has encountered a problem and needs to close. We are
sorry for the inconvenience."
As I mentioned above this program is working fine in VS.
I copy part of my code that read mails and split them for your reference.
public void ReadMail()
{
ServicePointManager.ServerCertificateValidationCallback += delegate(object sender,
X509Certificate certificate,
X509Chain chain,
SslPolicyErrors sslPolicyErrors) { return true; };
try
{
ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2007_SP1);
service.TraceEnabled = true;
service.Credentials = new WebCredentials(_username, _password); //Modify this
service.Url = new Uri(_exchange); //Modify this
service = new ExchangeService(ExchangeVersion.Exchange2007_SP1);
service.Url = new Uri(_exchange);
service.TraceEnabled = true;
service.Credentials = new WebCredentials(_username, _password); //Modify this
service.Url = new Uri(_exchange);
//SearchFilter to get unreaded messages only.
SearchFilter sf = new SearchFilter.SearchFilterCollection(LogicalOperator.And, new SearchFilter.IsEqualTo(EmailMessageSchema.IsRead, false));
ItemView itemview = new ItemView(Int16.MaxValue);
//DateTime searchdate = new DateTime(2012, 7, 6); //Year, month, day
SearchFilter greaterthanfilter = new SearchFilter.IsGreaterThan(ItemSchema.DateTimeSent, Convert.ToDateTime(startDate));
SearchFilter lessthanfilter = new SearchFilter.IsLessThan(ItemSchema.DateTimeSent,Convert.ToDateTime(finishDate));
SearchFilter[] f = { greaterthanfilter, lessthanfilter };
SearchFilter filter = new SearchFilter.SearchFilterCollection(LogicalOperator.And, f);
//Folder folder = Folder.Bind(this.m_Service, WellKnownFolderName.MsgFolderRoot); //Or the folder you want to search in
//FindItemsResults<Item> results = folder.FindItems(filter, new ItemView(1000));
FindItemsResults<Item> findResults = service.FindItems(WellKnownFolderName.SentItems,filter, itemview);
Action action = () => fr.setText(findResults.Items.Count + "mails need to analysis from "+startDate +" to "+ finishDate);
fr.Invoke(action, null);
action = () => fr.setMaximumProgressBar(findResults.Items.Count);
fr.Invoke(action, null);
dmd = new List<DailyMailDetails>();
foreach (Item item in findResults.Items)
{
string messageDate = "Error in Date";
string messageSubj = "Error in Subject";
int index = 0;
try
{
PropertySet propertySet = new PropertySet(BasePropertySet.FirstClassProperties, ItemSchema.DateTimeSent, ItemSchema.Body, ItemSchema.Subject);
propertySet.RequestedBodyType = BodyType.Text;
EmailMessage message = EmailMessage.Bind(service, item.Id, propertySet);
string temp = startSign.ToUpper();
int start = message.Body.Text.ToUpper().IndexOf(temp) + temp.Length;
int end = message.Body.Text.ToUpper().IndexOf(finishSign.ToUpper());
int len = end - start;
string text = message.Body.Text.Substring(start, len);
index = findDmdIndex(message.DateTimeSent.ToShortDateString().ToString());
if (index == -1)
{
dmd.Add(new DailyMailDetails(message.DateTimeSent.ToShortDateString().ToString(), (List<PeopleSigniture>)Extensions.Clone<PeopleSigniture>(OrginallistPeopleSign)));
index = dmd.Count - 1;
}
bool signExist = false;
for (int i = 0; i < listPeopleSign.Count; i++)
if (text.ToUpper().Contains(dmd[index].peopleSign[i].Signiture.ToUpper()))
{
dmd[index].peopleSign[i].addResponse(message.DateTimeSent.ToString(), message.Subject.ToString());
signExist = true;
break;
}
messageDate = message.DateTimeSent.ToString();
messageSubj = message.Subject.ToString();
if (!signExist)
dmd[index].peopleSign[dmd[index].peopleSign.Count - 2].addResponse(message.DateTimeSent.ToString(), message.Subject.ToString());
}
catch (Exception ex)
{
dmd[index].peopleSign[dmd[index].peopleSign.Count - 1].addResponse(messageDate, messageSubj);
}
action = () => fr.increasePrograss();
fr.Invoke(action, null);
}
}
catch (Exception ex)
{
MessageBox.Show("Class: Mail Function:ReadMail" + ex.Message);
}
Action action2 = () => fr.setText(ToString(true),dmd);
fr.Invoke(action2, null);
}
For issue #1 - you are viewing the XML output likely because you have EWS tracing enabled. You need to set ExchangeService.TraceEnabled to false or comment it out entirely. (You also have many duplicate lines of code you need to cleanup.)
service.TraceEnabled = false;
For issue #2 - you need to determine the actual .NET exception. Without this - we cannot help you further. It could be crashing for countless reasons. Please provide a stack trace.

How to retrieve recurring appointments

I am retrieving appoints from an exchange server using the service.FindItems method and it isn't returning recurring appointments. It returns the first instance of recurring items but no more after that and IsRecurring is set to false on the appointment.
This is the code:
private void loadUsersAppointments(string user, int rscID)
{
// Add a search filter that searches on the body or subject.
List<SearchFilter> searchFilterCollection = new List<SearchFilter>();
searchFilterCollection.Add(new SearchFilter.IsGreaterThan(AppointmentSchema.Start, DateTime.Today.AddDays(-7)));
// Create the search filter.
SearchFilter searchFilter = new SearchFilter.SearchFilterCollection(LogicalOperator.Or, searchFilterCollection.ToArray());
CalendarView V = new CalendarView(DateTime.Today.AddDays(-7), DateTime.Today.AddMonths(1), 1000);
V.PropertySet = new PropertySet(BasePropertySet.IdOnly, AppointmentSchema.Subject, AppointmentSchema.Start, AppointmentSchema.End);
V.Traversal = ItemTraversal.Shallow;
// Create a view with a page size of 50.
ItemView view = new ItemView(10000);
// Identify the Subject and DateTimeReceived properties to return.
// Indicate that the base property will be the item identifier
view.PropertySet = new PropertySet(BasePropertySet.IdOnly, AppointmentSchema.Subject, AppointmentSchema.Start, AppointmentSchema.End);
// Order the search results by the DateTimeReceived in descending order.
view.OrderBy.Add(AppointmentSchema.Start, SortDirection.Descending);
// Set the traversal to shallow. (Shallow is the default option; other options are Associated and SoftDeleted.)
view.Traversal = ItemTraversal.Shallow;
// Send the request to search the Inbox and get the results.
ExchangeService service = GlobalFunc.ElevateGetBinding();
service.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SmtpAddress, user+"#works.local");
FindItemsResults<Item> findResults = service.FindItems(WellKnownFolderName.Calendar, searchFilter, view);
List<Item> items = new List<Item>();
foreach (Microsoft.Exchange.WebServices.Data.Appointment appointment in findResults)
{
items.Add(appointment);
}
service.LoadPropertiesForItems(items, PropertySet.FirstClassProperties);
// Process each item.
foreach (Microsoft.Exchange.WebServices.Data.Appointment myItem in items)
{
DevExpress.XtraScheduler.Appointment AddAppt = new DevExpress.XtraScheduler.Appointment();
try {
if (myItem.Subject.StartsWith("Advisor Appointment"))
AddAppt.LabelId = 8;
else
AddAppt.LabelId = 2;
AddAppt.Subject = myItem.Subject;
}
catch { }
try
{
}
catch (Exception ex) { MessageBox.Show(ex.Message); }
try { AddAppt.Start = myItem.Start; }
catch { }
try { AddAppt.Description = myItem.Body; }
catch { }
try { AddAppt.End = myItem.End; }
catch { }
AddAppt.ResourceId = rscID;
schStorage.Appointments.Add(AddAppt);
}
}
Any ideas would be much appreciated.
Thanks
You need to use a CalendarView to get recurring appointments. Instances of recurring appointments are not real items in the Exchange database. Instead, Exchange creates virtual items on the fly when you query for a specific time range.

Categories

Resources