Share via


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 MessageType

  • Anonymous
    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

  1. process mail object and update some of the properties based on business logic (i.e spell check tool)
  2. 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).aspx

  • Anonymous
    October 02, 2008
    I've put together a list of articles which cover common questions on Exchange Web Services (EWS). These

  • Anonymous
    March 18, 2009
    The comment has been removed

  • Anonymous
    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.