HOWTO: EWS: Update IsRead Flag for items using Exchange Web Services
First thing first, you cannot use Exchange Web Services (as of now) to update the IsRead flag for items other than MessageType. MessageType has IsRead property in place to update the MAPI property PR_MESSAGE_FLAGS. Product group is aware of this limitation and very soon we should see an fix for this. In the mean time if you like to have a solution in place for all items (what I call as workaround), you can use WebDAV to update the IsRead flag for all other items.
//Check the item's message class to either use WebDAV or EWS to update the PR_MESSAGE_FLAGS (IsRead)
public static bool SetReadFlag(ItemIdType itemId, ReadStatus status)
{
bool retVal = false;
//Use EWS to set the IsRead flag if it's MessageType, else use WebDAV
if (GetItem(itemId.Id).ItemClass.StartsWith("IPM.Note", StringComparison.OrdinalIgnoreCase))
retVal = SetReadFlagForMessage(itemId, status);
else
retVal = WebDAV_SetIsRead(GetFlatspaceURI(itemId.Id), status);
return retVal;
}
//WebDAV code to update the IsRead flag, it uses OWA's FlatspaceURI to update the property
private static bool WebDAV_SetIsRead(string itemUrl, ReadStatus status)
{
// Variables.
bool retVal = false;
System.Net.HttpWebRequest Request;
System.Net.WebResponse Response;
string strBody = "";
byte[] bytes = null;
System.IO.Stream RequestStream;
// Build the PROPPATCH request body.
strBody = "<?xml version=\"1.0\"?>"
+ "<a:propertyupdate xmlns:a=\"DAV:\" xmlns:d=\"urn:schemas-microsoft-com:exch-data:\" "
+ "xmlns:b=\"urn:schemas:httpmail:\" xmlns:c=\"xml:\">"
+ "<a:set><a:prop><b:read>" + Convert.ToInt32((status == ReadStatus.Read ? true : false))
+ "</b:read></a:prop>"
+ "</a:set></a:propertyupdate>";
// Create the HttpWebRequest object.
Request = (System.Net.HttpWebRequest)HttpWebRequest.Create(itemUrl);
// Add the network credentials to the request.
Request.Credentials = ExchangeBinding.CurrentInstance.Credentials;
// Specify the method.
Request.Method = "PROPPATCH";
// Encode the body using UTF-8.
bytes = Encoding.UTF8.GetBytes((string)strBody);
// Set the content header length. This must be
// done before writing data to the request stream.
Request.ContentLength = bytes.Length;
// Get a reference to the request stream.
RequestStream = Request.GetRequestStream();
// Write the XML body to the request stream.
RequestStream.Write(bytes, 0, bytes.Length);
// Close the Stream object to release the connection
// for further use.
RequestStream.Close();
// Set the content type header.
Request.ContentType = "text/xml";
// Send the PROPPATCH method request and get the
// response from the server.
Response = (HttpWebResponse)Request.GetResponse();
retVal = true;
// Clean up.
Response.Close();
return retVal;
}
//EWS code to update the IsRead flag, *ONLY* for MessageType
private static bool SetReadFlagForMessage(ItemIdType messageId, ReadStatus status)
{
SetItemFieldType setField = new SetItemFieldType();
MessageType message = new MessageType();
if (status == ReadStatus.UnRead)
message.IsRead = false;
else
message.IsRead = true;
message.IsReadSpecified = true;
setField.Item1 = message;
PathToUnindexedFieldType path = new PathToUnindexedFieldType();
path.FieldURI = UnindexedFieldURIType.messageIsRead;
setField.Item = path;
ItemChangeType[] updatedItems = new ItemChangeType[1];
updatedItems[0] = new ItemChangeType();
updatedItems[0].Updates = new ItemChangeDescriptionType[1];
updatedItems[0].Updates[0] = setField;
ItemChangeDescriptionType[] updates = new ItemChangeDescriptionType[1];
updates[0] = new ItemChangeDescriptionType();
updates[0].Item = path;
updatedItems[0].Item = new ItemIdType();
((ItemIdType)updatedItems[0].Item).Id = messageId.Id;
((ItemIdType)updatedItems[0].Item).ChangeKey = messageId.ChangeKey;
UpdateItemType request = new UpdateItemType();
request.ItemChanges = updatedItems;
request.ConflictResolution = ConflictResolutionType.AutoResolve;
request.MessageDisposition = MessageDispositionType.SaveOnly;
request.MessageDispositionSpecified = true;
request.SendMeetingInvitationsOrCancellations = CalendarItemUpdateOperationType.SendToChangedAndSaveCopy;
request.SendMeetingInvitationsOrCancellationsSpecified = true;
UpdateItemResponseType response = ExchangeBinding.CurrentInstance.UpdateItem(request);
if (response.ResponseMessages.Items[0].ResponseClass != ResponseClassType.Success)
return false;
else
return true;
}
//Get the Flatspace URI , which can be consumed by WebDav
public static string GetFlatspaceURI(string itemId)
{
GetItemType getRequest = new GetItemType();
getRequest.ItemIds = new ItemIdType[1];
ItemIdType id = new ItemIdType();
//
id.Id = itemId;
getRequest.ItemIds[0] = id;
getRequest.ItemShape = new ItemResponseShapeType();
getRequest.ItemShape.BaseShape = DefaultShapeNamesType.IdOnly;
getRequest.ItemShape.AdditionalProperties = new PathToExtendedFieldType[1];
PathToExtendedFieldType PR_FLAT_URL_NAME = new PathToExtendedFieldType();
PR_FLAT_URL_NAME.PropertyTag = "0x670E";
PR_FLAT_URL_NAME.PropertyType = MapiPropertyTypeType.String;
getRequest.ItemShape.AdditionalProperties[0] = PR_FLAT_URL_NAME;
GetItemResponseType response = ExchangeBinding.CurrentInstance.GetItem(getRequest);
ResponseMessageType rmt = response.ResponseMessages.Items[0];
Console.WriteLine(rmt.ResponseClass.ToString());
if (rmt.ResponseCodeSpecified)
{
Console.WriteLine(rmt.ResponseCode);
}
ItemInfoResponseMessageType iirmt = rmt as ItemInfoResponseMessageType;
ItemType item = iirmt.Items.Items[0];
ExtendedPropertyType ept = item.ExtendedProperty[0];
return ept.Item.ToString();
}
Programming for Exchange 2007? You need Inside Microsoft Exchange 2007 Web Services
Comments
Anonymous
November 29, 2007
PingBack from http://msdnrss.thecoderblogs.com/2007/11/30/howto-ews-update-isread-flag-for-items-using-exchange-web-services/Anonymous
January 29, 2008
You can easily update "0x0E07" using ExtendedProperties. No need of WebDav.Anonymous
January 29, 2008
Can you share the sample with me, what version of exchange are you targetting... is it SP1 ?Anonymous
January 29, 2008
mail.IsRead = true/false; mail.IsReadSpecified = true; Try setting "IsReadSpecified" as true along with IsRead. It should work with both RTM and SP1. If not, PathToExtendedFieldType result = new PathToExtendedFieldType(); result.PropertyTag = "0x0E07"; result.PropertyType = MapiPropertyTypeType.Integer; ExtendedPropertyType property = new ExtendedPropertyType(); property.ExtendedFiledURI = result; property.Item = <value in string>; MessageType mail = new MessageType(); : : // Set all the properties : : // Set the extended property mail.ExtendedProperty = new ExtendedPropertyType[] {property}; : : // Call proxy.CreateItem() method. This way, you can avoid the second call.Anonymous
January 29, 2008
I think you have missed something in my blog, my code target both MessageType and all other folder items. As of today both RTM & SP1 cannot update IsRead for anything other than MessageType. I have used WebDAV just to mark the read flag on items other than MessageType, for MessageType we can use EWS and I am doing it in the above sample SetItemFieldType setField = new SetItemFieldType(); MessageType message = new MessageType(); if (status == ReadStatus.UnRead) message.IsRead = false; else message.IsRead = true; message.IsReadSpecified = true; setField.Item1 = message;Anonymous
January 29, 2008
Well, I missed it. Extended Property would work with ItemType as well.Anonymous
January 29, 2008
You cannot set the PR_MESSAGE_FLAG as it is a computed property, and there is no option of IsRead property in ItemType... it is available only for MessageTypeAnonymous
January 29, 2008
Not really... Check out David's reply in http://forums.microsoft.com/TechNet/ShowPost.aspx?PostID=1842684&SiteID=17 Vikas, in your case you can always build the values for computed properties. for eg., Lets look at Appointment State. 0x0001 - Appointment is a meeting 0x0002 - Appointment has been received 0x0004 - Appointment is cancelled 0x0003 - Appointment is a meeting and has been recieved (Combination of 1 & 2). If you are able to set the property at the time of creation itself, why would you need the second call?Anonymous
January 29, 2008
"If you are able to set the property at the time of creation itself, why would you need the second call?" I want to mark an existing item as read/unread, thats how this sample came. "This logic is in store and enshrined in MAPI docs - most bits in PR_MESSAGE_FLAGS cannot be set once SaveChanges has been called for the first time on a message."Anonymous
January 29, 2008
Well, if that is the case you can use WebDAV to retrieve the URI. EWS is costly. It can do magic when it works with TNEF. Try out.Anonymous
July 14, 2008
Hello I am interested in updating mail properties / attributes before mail has been sent. Consider a case :OWA plug-in 1)User open OWA 2)create a new mail 3)Click on send mail
- process mail object and update some of the properties based on business logic (i.e spell check tool)
- let mail send in normal flow let me know if EWS has specific methods to add or update attributes of Mail item
Anonymous
September 25, 2008
EWS does not have such functionality you might want to look for OWA customizations in Exchange 2007 SP1 References: http://msdn.microsoft.com/en-us/library/bb891803(EXCHG.80).aspxAnonymous
October 02, 2008
I've put together a list of articles which cover common questions on Exchange Web Services (EWS). TheseAnonymous
March 18, 2009
The comment has been removedAnonymous
April 16, 2009
Hi All, I was wondering if EWS coulf be used to set MAPI attributes such as PR_CONVERSATION_INDEX in an outgoing email item. If this is at all possible I would greatly appreciate if someone can explain how I can go about doing this Thanks.Anonymous
August 26, 2009
Thanx man! Your code was a big help te me.