Andre Pageot
Andre Pageot

Reputation: 336

Exchange Web service (EWS) chain FindItemType for itemItemclas & messageIsRead

High fellow coders.

I'm using the raw exchange web service, referenced in my SSIS script task.

My issue is that when I enumerate items in a mailbox or folder, Not only am I interested in only those items that have not been read, but I want to ignore all the system type messages. so I only want items, specifically messages, who's "itemclass" is "IPM.Note" nothing else.

Here is a definitive list of Item Types and Message classes https://msdn.microsoft.com/en-us/library/office/ff861573.aspx

my code which works successfully for unread items in the inbox

 'declare my find criteria, return only the IDs, from the inbox, for unread items
    Dim reqFindUnreadMailInInbox As FindItemType = New FindItemType With _
    {.Traversal = ItemQueryTraversalType.Shallow _
     , .ItemShape = New ItemResponseShapeType With {.BaseShape = DefaultShapeNamesType.IdOnly} _
     , .ParentFolderIds = New DistinguishedFolderIdType(0) {New DistinguishedFolderIdType With {.Id = DistinguishedFolderIdNameType.inbox}} _
     , .Restriction = New RestrictionType With _
        {.Item = New IsEqualToType With _
        {.Item = New PathToUnindexedFieldType With {.FieldURI = UnindexedFieldURIType.messageIsRead} _
                                                    , .FieldURIOrConstant = New FieldURIOrConstantType With {.Item = New ConstantValueType With {.Value = "0"}} _
                                                } _
        } _
    }

    'go fetch the response from exchange
    Dim resFindItemResponse As FindItemResponseType = esb.FindItem(reqFindUnreadMailInInbox)
    Dim resFindFolderMessages As FindItemResponseMessageType = resFindItemResponse.ResponseMessages.Items(0)
    Dim resFolderItems As ArrayOfRealItemsType = Nothing '= New ArrayOfRealItemsType

The problem I have is I want to add a restriction on the itemClass that is returned. But cannot figure out how to add a second Restriction to the request. This is what the restriction would look like if I changed my search to pull all items from the inbox regardless of read state but restricting only to itemClass IPM.Note (note the addition of the paged result)

 Dim reqFindUnreadMailInInbox As FindItemType = New FindItemType With _
   {.Item = New IndexedPageViewType With {.MaxEntriesReturnedSpecified = True, .MaxEntriesReturned = "100", .BasePoint = IndexBasePointType.Beginning, .Offset = 0} _
    , .Traversal = ItemQueryTraversalType.Shallow _
    , .ItemShape = New ItemResponseShapeType With {.BaseShape = DefaultShapeNamesType.IdOnly} _
    , .ParentFolderIds = New DistinguishedFolderIdType(0) {New DistinguishedFolderIdType With {.Id = DistinguishedFolderIdNameType.inbox}} _
    , .Restriction = New RestrictionType With _
       {.Item = New IsEqualToType With _
                                   {.Item = New PathToUnindexedFieldType With {.FieldURI = UnindexedFieldURIType.itemItemClass} _
                                                , .FieldURIOrConstant = New FieldURIOrConstantType With {.Item = New ConstantValueType With {.Value = "IPM.Note"}} _
                                   } _
       } _
   }

The next chunk of code checks for an error, and proceeds to enumerate the IDs and fetch the items in one call. If I debug the resGetitem after the response has returned, I can drill down and look at each items class by looking in the immediate window with this query

?directcast(directcast(resGetItem.ResponseMessages.Items(0),ItemInfoResponseMessageType).Items.Items(0),MessageType)

and I can see "REPORTS.IPM.Note.NDR". The question is how can I filter the initial call to restrict to only "IPM.Note"

 'if there was an error bur out and report
    If resFindFolderMessages.ResponseClass = ResponseClassType.[Error] Then
        Throw New Exception(resFindFolderMessages.MessageText)
    Else
        TraceLog.AppendLine("Inbox found, ID pulled back")
        If Not IsNothing(DirectCast(resFindFolderMessages.RootFolder.Item, ArrayOfRealItemsType).Items) Then
            resFolderItems = resFindFolderMessages.RootFolder.Item
            TraceLog.AppendLine(String.Format("found {0} unread mail - start processing", resFolderItems.Items.Count))
            'So we have the array of ids for the emails, now fetch the emails themselves
            Dim resItemIDs As ItemIdType() = Nothing
            'collect the ids up
            For x As Integer = 0 To resFolderItems.Items.Count - 1
                If IsNothing(resItemIDs) Then ReDim resItemIDs(0) Else ReDim Preserve resItemIDs(resItemIDs.Length)
                resItemIDs(x) = resFolderItems.Items(x).ItemId
            Next
            'go get the email messages
            Dim resGetItem As GetItemResponseType = esb.GetItem(New GetItemType With { _
                                                                .ItemShape = New ItemResponseShapeType With {.BaseShape = DefaultShapeNamesType.AllProperties _
                                                                                                             , .BodyType = BodyTypeResponseType.Text _
                                                                                                             , .BodyTypeSpecified = True} _
                                                                , .ItemIds = resItemIDs})
            'declare and fill up the message array that we are going to return
            Dim resItemMessage As ItemType() = Nothing
            For x As Integer = 0 To resGetItem.ResponseMessages.Items.Length - 1
                If IsNothing(resItemMessage) Then ReDim resItemMessage(0) Else ReDim Preserve resItemMessage(resItemMessage.Length)
                resItemMessage(x) = DirectCast(resGetItem.ResponseMessages.Items(x), ItemInfoResponseMessageType).Items.Items(0)
            Next
            'pass back the emails
            Return resItemMessage
        Else
            TraceLog.AppendLine("no unread mail found closing out")
            Return Nothing
        End If
    End If

========== UPDATE ============

With a nudge in the right direction from Glen Scales we have Success! EWS is a mine field of types and derived types.

'create the finditemtype and load the restrictions
    'first only the unread messages
    'secondly, only of type "IPM.Note" ie just emails
    Dim reqFindUnreadMailInInbox As FindItemType = New FindItemType With _
    {.Traversal = ItemQueryTraversalType.Shallow _
     , .ItemShape = New ItemResponseShapeType With {.BaseShape = DefaultShapeNamesType.IdOnly} _
     , .ParentFolderIds = New DistinguishedFolderIdType(0) {New DistinguishedFolderIdType With {.Id = DistinguishedFolderIdNameType.inbox}} _
     , .Restriction = New RestrictionType With {.Item = New AndType With { _
    .Items = New IsEqualToType() { _
     New IsEqualToType With {.Item = New PathToUnindexedFieldType With { _
                              .FieldURI = UnindexedFieldURIType.messageIsRead} _
                            , .FieldURIOrConstant = New FieldURIOrConstantType With {.Item = New ConstantValueType With {.Value = "0"}} _
                            } _
     , New IsEqualToType With {.Item = New PathToUnindexedFieldType With { _
                               .FieldURI = UnindexedFieldURIType.itemItemClass} _
                                , .FieldURIOrConstant = New FieldURIOrConstantType With {.Item = New ConstantValueType With {.Value = "IPM.Note"}} _
                                } _
    }}}}

Thanks goes to Glen Scales!

Upvotes: 0

Views: 260

Answers (1)

Glen Scales
Glen Scales

Reputation: 22032

You need to use the AndType https://msdn.microsoft.com/en-us/library/office/exchangewebservices.andtype(v=exchg.150).aspx

Then define and add two isEqual Restrictions to that eg

RestrictionType restriction = new RestrictionType();
AndType andType = new AndType();
andType.Items = new SearchExpressionType[] { IsEqual1,IsEqual2 };
restriction.Item = andType;

Cheers Glen

Upvotes: 1

Related Questions