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);
}
Related
Using Exchange 2013 SP1 and Exchange Web Services managed API 2.2 to try and get a list of the contacts in a contact folder that I have stored in Public Folders. I would like to limit the size of the ItemView to the total number of contacts that I have in this contact folder, but when I try to return that property (contactfolder.TotalCount) it always returns 0. If I try this with using the Contact folder under my mailbox a value other than 0 is returned. I can get around this issue by either specifying a value for the constructor for the ItemView as either a specific number or by using int.MaxValue, but I would rather use the total number of items that are in the contact list. Any assistance is greatly appreciated! Here is the relevant code:
private FindItemsResults<Microsoft.Exchange.WebServices.Data.Item> ExchangeContacts()
{
// Setup the exchange server connection.
ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2013_SP1);
service.AutodiscoverUrl("someone#mydomain.com");
// Set the filter to choose the correct contact list
SearchFilter filter = new SearchFilter.IsEqualTo(FolderSchema.DisplayName, "My Public Contacts");
SearchFilter.SearchFilterCollection filterCollection = new SearchFilter.SearchFilterCollection();
filterCollection.Add(filter);
// Get the FolderId using the search filter.
Folder parent = Folder.Bind(service, WellKnownFolderName.PublicFoldersRoot);
FindFoldersResults results = parent.FindFolders(filter, new FolderView(1));
FolderId fid = results.Single().Id;
// Get the Contact folder based on the folderid.
ContactsFolder contactsfolder = (ContactsFolder)results.Single();
ItemView view = new ItemView(contactsfolder.TotalCount);
// Set the property that need to be shown in the page.
view.PropertySet = new PropertySet(BasePropertySet.IdOnly, ContactSchema.DisplayName, ContactSchema.CompanyName, ContactSchema.LastModifiedTime, ContactSchema.BusinessAddressCity, ContactSchema.BusinessAddressPostalCode, ContactSchema.BusinessAddressState, ContactSchema.BusinessAddressStreet, ContactSchema.HomeAddressCity, ContactSchema.HomeAddressPostalCode, ContactSchema.HomeAddressState, ContactSchema.HomeAddressStreet, ContactSchema.ItemClass, ContactSchema.FileAs, ContactSchema.LastModifiedName);
//view.PropertySet = new PropertySet(BasePropertySet.IdOnly, ContactSchema.DisplayName);
// Order the results by one of the selected properties
//view.OrderBy.Add(ContactSchema.LastModifiedTime, Microsoft.Exchange.WebServices.Data.SortDirection.Descending);
FindItemsResults<Microsoft.Exchange.WebServices.Data.Item> contactItems = contactsfolder.FindItems(view);
return contactItems;
}
I recreated your public folder (immediately under the public folder root), added a contact to it, and ran your code and get a contactItems.TotalCount value of 1 (as expected). However, after discussing this with the Exchange product team I learned that FindFolder can return an incorrect value if the FindFolder request gets routed to the public folder mailbox that doesn't have the content of the public folder. So TotalCount can return an incorrect value and is not supported for public folders. We will get the documentation updated to reflect this issue.
FindFolder operation (Exchange 2013):
Using the Default value for the BaseShape, the response returns the
folder name, the folder ID, the number of subfolders, the number of
child folders found in the folder, and the count of unread items.
<...>
FindFolder responses to a request with the AllProperties response
shape will not return the TotalCount and UnreadCount elements for
public folder searches.
Guess you need to specify a property filter in the search criteria.
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));
I have stumbled upon a problem where the Outlook items table sort method does not give desired results - despite the ascending or descending the method GetLast() always returns the same email item. Code as follows:
Application olApp = new Application();
NameSpace olNS = olApp.GetNamespace("MAPI");
MAPIFolder oFolder = olNS.GetDefaultFolder(OlDefaultFolders.olFolderInbox);
Explorer oExp = oFolder.GetExplorer(false);
//olNS.Logon( false, true);
result = new IOActionResult(null);
oFolder.Items.Sort("[ReceivedTime]");
var subject = oFolder.Items.GetLast().Subject;
I have tried specifying following:
oFolder.Items.Sort("[ReceivedTime]", true);
oFolder.Items.Sort("[ReceivedTime]", false);
oFolder.Items.Sort("[ReceivedTime]", OlSortOrder.olAscending);
oFolder.Items.Sort("[ReceivedTime]", OlSortOrder.olDescending);
Which did not seem to work either... Any thoughts appreciated!
On your last line;
var subject = oFolder.Items.GetLast().Subject;
You are being returned a new Items object from Outlook, so your sort was actually performed on an instance that you no longer have a reference to.
Change your code to look like this;
Application olApp = new Application();
NameSpace olNS = olApp.GetNamespace("MAPI");
MAPIFolder oFolder = olNS.GetDefaultFolder(OlDefaultFolders.olFolderInbox);
Items items = oFolder.Items;
items.Sort("[ReceivedTime]");
var subject = items.GetLast().Subject;
A good rule of thumb when developing against Outlook is to always assign intermediary members of objects to their own local variable. This is particular relevant for releasing them later on.
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 :)
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.