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