I am using Exchange Web Services to try to get a list of all Outlook tasks which are not complete.
I have an instance of ExchangeService, and attempt to find all incomplete tasks like this:
SearchFilter searchFilter = new SearchFilter.IsNotEqualTo(TaskSchema.Status, TaskStatus.NotStarted);
FindItemsResults<Item> tasks = service.FindItems(WellKnownFolderName.Tasks, searchFilter, view);
However, on the last line, I get a "ServiceResponseException: The specified value is invalid for property." This seems weird to me because the EWS documentation explicitly states that the Task.Status is supposed to be one of the TaskStatus enumeration values. Creating a SearchFilter which compares against a string value does not cause an exception, but I haven't tried any of the other enumeration options to see whether they give the same behavior.
I am able to do this using ExtendedPropertyDefinition with Exchange 2007.
I am using PidLidTaskComplete Canonical Property.
Full list of named properties available here.
//Create the extended property definition.
ExtendedPropertyDefinition taskCompleteProp = new ExtendedPropertyDefinition(DefaultExtendedPropertySet.Task, 0x0000811C, MapiPropertyType.Boolean);
//Create the search filter.
SearchFilter.IsEqualTo filter = new SearchFilter.IsEqualTo(taskCompleteProp, false);
//Get the tasks.
FindItemsResults<Item> tasks = service.FindItems(WellKnownFolderName.Tasks, filter, new ItemView(50));
I believe you may also achieve that without using any magic numbers:
var view = new ItemView(20);
var query = new SearchFilter.IsNotEqualTo(TaskSchema.IsComplete, true);
var results = exchangeService.FindItems(WellKnownFolderName.Tasks, query, view);
This does work on a certain version of exchange :)
Related
This has been working perfectly for probably a year or more, then suddenly, I think as of Saturday October 12th it started failing (FindResults returns no items);
//Tag the sent email so we can pull it back in a moment
Guid myPropertySetId = new Guid("{375a1079-a049-4c2d-a2e1-983d588cbed4}");
ExtendedPropertyDefinition myExtendedPropertyDefinition = new ExtendedPropertyDefinition(myPropertySetId, "TelEmailGuid", MapiPropertyType.String);
Guid telEmailGuid = Guid.NewGuid();
message.SetExtendedProperty(myExtendedPropertyDefinition, telEmailGuid.ToString());
//Send the email
message.SendAndSaveCopy(completedFolder);
//Find the sent email
ItemView view = new ItemView(1);
SearchFilter searchFilter = new SearchFilter.IsEqualTo(myExtendedPropertyDefinition, telEmailGuid.ToString());
view.PropertySet = new PropertySet(BasePropertySet.IdOnly);
FindItemsResults<Item> findResults = service.FindItems(completedFolder, searchFilter, view);
return DownloadEmail(findResults.FirstOrDefault().Id.ToString());
I tried tweaking things a little to wait before trying to find the e-mail, this has helped (now maybe 10% succeed). So, I then added a loop, so if not found it will try again a few times. But it seems that if it isn't found the first time, it is not found on subsequent attempts;
//Tag the sent email so we can pull it back in a moment
Guid myPropertySetId = new Guid("{375a1079-a049-4c2d-a2e1-983d588cbed4}");
ExtendedPropertyDefinition myExtendedPropertyDefinition = new ExtendedPropertyDefinition(myPropertySetId, "TelEmailGuid", MapiPropertyType.String);
Guid telEmailGuid = Guid.NewGuid();
message.SetExtendedProperty(myExtendedPropertyDefinition, telEmailGuid.ToString());
//Send the email
message.SendAndSaveCopy(completedFolder);
//Find the sent email
ItemView view = new ItemView(1);
SearchFilter searchFilter = new SearchFilter.IsEqualTo(myExtendedPropertyDefinition, telEmailGuid.ToString());
view.PropertySet = new PropertySet(BasePropertySet.IdOnly);
int attempt = 1;
System.Threading.Thread.Sleep(1000);
FindItemsResults<Item> findResults = service.FindItems(completedFolder, searchFilter, view);
while (findResults.TotalCount == 0 && attempt < 5)
{
findResults = service.FindItems(completedFolder, searchFilter, view);
attempt++;
}
return DownloadEmail(findResults.FirstOrDefault().Id.ToString());
Does anyone have any suggestions? I suspect it is a Microsoft issue but perhaps a different approach might allow us to workaround the issue.
It sounds like its an issue with the Search timing out because your not searching an indexed property as the FolderItem Count grow the performance of the search will decline over time (also other factors like server load etc will have a direct effect when searching for item in a Folder with a large item count).
Your search looks pretty static so you could create a Search Folder https://learn.microsoft.com/en-us/previous-versions/office/developer/exchange-server-2010/dd633690(v%3Dexchg.80) which would optimize the search.
The other thing you maybe be able to do is add a DateTime restriction for the search eg I have code that searches for messages based on the Internet MessageId and it has a similar problem when Item counts get large the search times out. So because I know what I'm searching for are always recent email adding a Date Time restriction fixed the issue in this instance eg
SearchFilter internetMessageIdFilter = new SearchFilter.IsEqualTo(PidTagInternetMessageId, InternetMessageId);
SearchFilter DateTimeFilter = new SearchFilter.IsGreaterThan(EmailMessageSchema.DateTimeReceived, DateTime.Now.AddDays(-1));
SearchFilter.SearchFilterCollection searchFilterCollection= new SearchFilter.SearchFilterCollection(LogicalOperator.And);
searchFilterCollection.Add(internetMessageIdFilter);
searchFilterCollection.Add(DateTimeFilter);
I have a Windows Service written in C# that polls an Exchange server to process mails to an unattended email box.
It's been working fine, until today when it's throwing up the following error:-
EXCEPTION: Microsoft.Exchange.WebServices.Data.ServiceVersionException: The property Hashtags is valid only for Exchange Exchange2015 or later versions.
at Microsoft.Exchange.WebServices.Data.PropertyBag.set_Item(PropertyDefinition propertyDefinition, Object value)
at Microsoft.Exchange.WebServices.Data.ComplexPropertyDefinitionBase.InternalLoadFromXml(EwsServiceXmlReader reader, PropertyBag propertyBag)
at Microsoft.Exchange.WebServices.Data.ComplexPropertyDefinitionBase.LoadPropertyValueFromXml(EwsServiceXmlReader reader, PropertyBag propertyBag)
at Microsoft.Exchange.WebServices.Data.PropertyBag.LoadFromXml(EwsServiceXmlReader reader, Boolean clear, PropertySet requestedPropertySet, Boolean onlySummaryPropertiesRequested)
at Microsoft.Exchange.WebServices.Data.ServiceObject.LoadFromXml(EwsServiceXmlReader reader, Boolean clearPropertyBag, PropertySet requestedPropertySet, Boolean summaryPropertiesOnly)
at Microsoft.Exchange.WebServices.Data.EwsServiceXmlReader.ReadServiceObjectsCollectionFromXml[TServiceObject](XmlNamespace collectionXmlNamespace, String collectionXmlElementName, GetObjectInstanceDelegate`1 getObjectInstanceDelegate, Boolean clearPropertyBag, PropertySet requestedPropertySet, Boolean summaryPropertiesOnly)
at Microsoft.Exchange.WebServices.Data.EwsServiceXmlReader.ReadServiceObjectsCollectionFromXml[TServiceObject](String collectionXmlElementName, GetObjectInstanceDelegate`1 getObjectInstanceDelegate, Boolean clearPropertyBag, PropertySet requestedPropertySet, Boolean summaryPropertiesOnly)
at Microsoft.Exchange.WebServices.Data.GetItemResponse.ReadElementsFromXml(EwsServiceXmlReader reader)
at Microsoft.Exchange.WebServices.Data.ServiceResponse.LoadFromXml(EwsServiceXmlReader reader, String xmlElementName)
at Microsoft.Exchange.WebServices.Data.MultiResponseServiceRequest`1.ParseResponse(EwsServiceXmlReader reader)
at Microsoft.Exchange.WebServices.Data.ServiceRequestBase.ParseResponse(EwsServiceXmlReader reader, WebHeaderCollection responseHeaders)
at Microsoft.Exchange.WebServices.Data.ServiceRequestBase.ReadResponse(EwsServiceXmlReader ewsXmlReader, WebHeaderCollection responseHeaders)
at Microsoft.Exchange.WebServices.Data.SimpleServiceRequestBase.ReadResponseXml(Stream responseStream, WebHeaderCollection responseHeaders)
at Microsoft.Exchange.WebServices.Data.SimpleServiceRequestBase.ReadResponse(IEwsHttpWebResponse response)
at Microsoft.Exchange.WebServices.Data.SimpleServiceRequestBase.InternalExecute()
at Microsoft.Exchange.WebServices.Data.MultiResponseServiceRequest`1.Execute()
at Microsoft.Exchange.WebServices.Data.ExchangeService.InternalLoadPropertiesForItems(IEnumerable`1 items, PropertySet propertySet, ServiceErrorHandling errorHandling)
at Microsoft.Exchange.WebServices.Data.ExchangeService.LoadPropertiesForItems(IEnumerable`1 items, PropertySet propertySet)
at MyServiceName.MyServiceName.CheckForNewEmails(ExchangeService service) in C:\TFSOnline\RPM Tools\MyServiceName\MyServiceName\MyServiceName.cs:line 177
at MyServiceName.MyServiceName.RunACheck(Object state) in C:\TFSOnline\RPM Tools\MyServiceName\MyServiceName\MyServiceName.cs:line 117
The line causing the crash is:
PropertySet properties = (BasePropertySet.FirstClassProperties);
service.LoadPropertiesForItems(emails, properties);
The specific error is:
Microsoft.Exchange.WebServices.Data.ServiceVersionException:
The property Hashtags is valid only for Exchange Exchange2015 or later versions.
I'm not using or accessing Hashtags anywhere, so presumably it's contained in BasePropertySet.FirstClassProperties.
As I mentioned, I've been using the above code quite happily up to now, it's only started giving this error today.
I'm using the latest EWS Stable Build: Exchange.WebServices.Managed.Api 2.2.1.1
BasePropertySet only has one other item, IdOnly, and the property I'm after is InternetMessageId, so I figured I'd just use that:
PropertySet properties = (BasePropertySet.IdOnly);
service.LoadPropertiesForItems(emails, properties);
Turns out InternetMessageId isn't covered by the property to get IDs...
EXCEPTION: Microsoft.Exchange.WebServices.Data.ServiceObjectPropertyException:
You must load or assign this property before you can read its value.
at Microsoft.Exchange.WebServices.Data.PropertyBag.get_Item(PropertyDefinition propertyDefinition)
at Microsoft.Exchange.WebServices.Data.EmailMessage.get_InternetMessageId()
The section of code giving the error hasn't changed, and as far as I can tell there's been no update to Office 365 that's affected Exchange.
To double-check, I took a previous version (compiled code, not source code that I recompiled) and installed that instead: still got the same error.
Anyone had this error before? I've Googled it but didn't get a single hit.
Edit: Tried installing the service on another machine on the off-chance it was specific to the machine it had been on.
Still get the same error, even with the previous code.
This code worked for me. I needed to add "new PropertySet" to get it to work.
foreach (var email in emails)
{
try {
var list = new List<EmailMessage> { email };
PropertySet properties = new PropertySet(BasePropertySet.FirstClassProperties);
service.LoadPropertiesForItems(list, properties);
<Process Email>
}
}
But what finally made it work was setting the Exchange version from Exchange2013 to Exchange2015:
Old Code:
service = new ExchangeService(ExchangeVersion.Exchange2013)
{
Credentials = new WebCredentials(user, password),
TraceEnabled = false,
TraceFlags = TraceFlags.None
};
New code:
service = new ExchangeService(ExchangeVersion.Exchange2015)
{
Credentials = new WebCredentials(user, password),
TraceEnabled = false,
TraceFlags = TraceFlags.None
};
I had this same issue. I noticed that you and I both did not specify which exchange server we were using. That worked for me for a long time but eventually I got this error. Specifying which exchange server fixed this for me.
You could also try setting the requestedServerVersion in the ExchangeService constructor explicitly to something higher. If this involves Office365, bear in mind that EWS is not receiving further updates.
Solved it. Turns out it was something in a specific email.
Originally the code was ordered as:-
PropertySet properties = (BasePropertySet.FirstClassProperties);
service.LoadPropertiesForItems(emails, properties);
foreach (var email in emails)
{
try {
<Process Email>
}
}
I re-ordered the code as:-
foreach (var email in emails)
{
try {
var list = new List<EmailMessage> { email };
PropertySet properties = (BasePropertySet.FirstClassProperties);
service.LoadPropertiesForItems(list, properties);
<Process Email>
}
}
So, getting the properties individually for each email, rather than all together. Has to be done via a List, as that's what LoadPropertiesForItems takes.
In this case, one of the emails has something (presumably the Hashtags property) which is causing the error.
Now all the rest of the emails get processed correctly, and the one that causes the error is skipped.
Although annoyingly, because I can't access the properties I can't actually log any information about it.
Try not to use PropertySet properties = (BasePropertySet.FirstClassProperties);, because it will likely return fields more than you need. (more than 50 properties)
Try load those you need it.
PropertySet ps = new PropertySet(
ItemSchema.Subject,
ItemSchema.InReplyTo,
ItemSchema.Body,
ItemSchema.DateTimeSent,
ItemSchema.DisplayTo,
ItemSchema.Importance,
EmailMessageSchema.From,
ItemSchema.UniqueBody,
ItemSchema.MimeContent,
ItemSchema.HasAttachments,
ItemSchema.Attachments
);
You could also try setting the requestedServerVersion in the ExchangeService constructor explicitly to something higher. For Office365, bear in mind that EWS is not receiving further updates.
I am very new to EWS and Exchange in general, so not really sure what is the best approach.
Background
I am trying to set configuration information about a room. I was hoping that the EWS API provided me with a Room object that I can add ExtendedProperties on, however, it appears that rooms are just an email address.
I then saw that each room had a CalendarFolder associated with it, so I am now trying to set the room configuration in the CalendarFolder, which is what the original question below refers to.
Original Question
I am trying to do a simple update of a CalendarFolder using:
var folderId = new FolderId(WellKnownFolderName.Calendar, new Mailbox(roomEmail.Address));
var myCalendar = CalendarFolder.Bind(service, folderId, PropertySet.FirstClassProperties);
myCalendar.DisplayName += "Updated";
myCalendar.Update();
However, when I call .Update() I get "The folder save operation failed due to invalid property values."
I believe that the problem might have something to do with myCalendar not having all of the properties that the calendar folder has on the server. So when I update the object it is only sending a partial object which is causing validation errors.
How would I go about updating a CalendarFolder?
After further research
I also stumbled across the following, which does work:
FindFoldersResults root = service.FindFolders(WellKnownFolderName.Calendar, new FolderView(500));
foreach (var folder in root.Folders)
{
folder.DisplayName = "confRoom1";
folder.Update();
}
I'm sure there is a difference between the two approaches, but I don't understand the differences between the folder that I get using the different query methods:
new FolderId(WellKnownFolderName.Calendar, new Mailbox(roomEmail.Address));
var myCalendar = CalendarFolder.Bind(service, folderId, PropertySet.FirstClassProperties);
and
service.FindFolders(WellKnownFolderName.Calendar, new FolderView(500));
Which approach would give me the correct CalendarFolder where I can set the ExtendedProperties for the room?
I'm sure there is a difference between the two approaches, but I don't understand the differences between the folder that I get using the different query methods:
new FolderId(WellKnownFolderName.Calendar, new Mailbox(roomEmail.Address));
var myCalendar = CalendarFolder.Bind(service, folderId, PropertySet.FirstClassProperties);
and
service.FindFolders(WellKnownFolderName.Calendar, new FolderView(500));
The First binds to the default calendar folder in a Mailbox and the second get the subfolders within the Default calendar folder. You can rename the subfolders within the default calendar folder because they are user created. You cannot rename the Default calendar folder in a Mailbox because its a special folder. If you want to set a Extended property (which you can do on a special folder then it easy just define it and set it) eg
ExtendedPropertyDefinition MyCustomProp = new ExtendedPropertyDefinition(DefaultExtendedPropertySet.PublicStrings, "MyCustomProp", MapiPropertyType.String);
CalendarFolder CalendarFolder = CalendarFolder.Bind(service,new FolderId(WellKnownFolderName.Calendar, "user#domain.com"));
CalendarFolder.SetExtendedProperty(MyCustomProp, "My Value");
CalendarFolder.Update();
What you want to get that value you must define a propertySet that tells exchange to return that value when you either Bind or use FindItems (Exchange will not return your property by default) eg
PropertySet MyPropSet = new PropertySet(BasePropertySet.FirstClassProperties);
MyPropSet.Add(MyCustomProp);
CalendarFolder = CalendarFolder.Bind(service, new FolderId(WellKnownFolderName.Calendar, "mailbox#domain.com"),MyPropSet);
Object PropValue = null;
if (CalendarFolder.TryGetProperty(MyCustomProp, out PropValue))
{
Console.WriteLine(PropValue);
}
Do you have any experiences with SearchFilter of EWS? I'm trying to get tasks with last modified time newer than value of variable date. It works with this code really in weird way, I've also tried to change date to UTC time format. Any advice what I'm doing wrong?
//Create the extended property definition.
ExtendedPropertyDefinition taskLastUpdate = new ExtendedPropertyDefinition(DefaultExtendedPropertySet.Task, 0x3008, MapiPropertyType.SystemTime);
//Create the search filter.
SearchFilter.IsGreaterThanOrEqualTo filter = new SearchFilter.IsGreaterThanOrEqualTo(taskLastUpdate, date.ToString("s") + "Z");
//Get the tasks.
FindItemsResults<Item> tasks = _service.FindItems(WellKnownFolderName.Tasks, filter, new ItemView(100));
I'm not sure why it didn't work way with ExtendedPropertyDefinition.
Solution:
SearchFilter greaterthanfilter = new SearchFilter.IsGreaterThanOrEqualTo(ItemSchema.LastModifiedTime, date );
SearchFilter filter = new SearchFilter.SearchFilterCollection(LogicalOperator.And, greaterthanfilter);
Folder folder = Folder.Bind(_service, WellKnownFolderName.Tasks); //Or the folder you want to search in
FindItemsResults<Item> results = folder.FindItems(filter, new ItemView(1000));
We're using EWS to generate some analytics on some of our mailboxes.
Part of this is getting a count/name/start/end of conversations. A conversation being analogous to the way Outlook 2010 shows them when grouping by conversation.
I was hoping to be able to use the ConversationId to group items, but that seems to be an Exchange 2010-only feature.
I can group by subject within a folder to get a simple idea of threads... however this does not handle split conversations, as Outlook 2010 does - specifically, it doesn't handle bringing in the replies that are in the sent items (these are important to us - we can't get good metrics without also looking at replies).
My current code for getting thread info looks like this:
private IEnumerable<EmailThread> GetThreads(Folder folder)
{
var view = new ItemView(int.MaxValue) {PropertySet = new PropertySet(BasePropertySet.IdOnly)};
// view.PropertySet.Add(ItemSchema.ConversationId); - Can't use this as we're stuck on Exchange 2007 !!!
view.PropertySet.Add(ItemSchema.Subject);
view.PropertySet.Add(ItemSchema.DateTimeReceived);
var grouping = new Grouping(ItemSchema.Subject, SortDirection.Descending, ItemSchema.DateTimeReceived, AggregateType.Maximum);
var groupResults = folder.FindItems(view, grouping);
return groupResults.Select(x => new EmailThread
{
Name = x.Items.First().Subject,
Items = x.Items.Count,
StartDate = x.Items.Last().DateTimeReceived, // Assume last in thread is first email
EndDate = x.Items.First().DateTimeReceived // Assume first in thread is most recent
});
}
I am hoping someone knows of a neat way to efficiently get information on replies that constitute part of a conversation?
You can fetch the ConversationId and the ConversationIndex via extended properties:
private static readonly ExtendedPropertyDefinition ConversationIdProperty = new ExtendedPropertyDefinition(0x3013, MapiPropertyType.Binary);
private static readonly ExtendedPropertyDefinition ConversationIndexProperty = new ExtendedPropertyDefinition(0x0071, MapiPropertyType.Binary);
var items = service.FindItems(WellKnownFolderName.Inbox, new ItemView(512) { PropertySet = new PropertySet(BasePropertySet.FirstClassProperties,
ConversationIdProperty, ConversationIndexProperty)});
Both are binary properties. Their content is described in great detail here:
[MS-OXOMSG]: E-Mail Object Protocol Specification, section 2.2.1.2 and 2.2.1.3.
The properties themselves are defined in [MS-OXPROPS]: Exchange Server Protocols Master Property List.