Sample code for 30+ languages & platforms
PureBasic

Outlook -- Search Multiple Folders

See more Outlook Examples

I don't yet see how it's possible to do a recursive search of Outlook folders using the Microsoft Graph API. My best guess is to somehow use OData v4.0's $expand query option, but the hierarchical structure of the "mailFolder" and "messages" Microsoft Graph resources don't quite fit. Suggestions are welcome and can be sent to support@chilkatsoft.com.

This example will iterate over a list of folder previously obtained by a recursive traversal of the Outlook mail folders. (See the link in the example code below.)

A separate search is performed on each desired folder, and the results are combined into a single result set.

Note: This example requires Chilkat v9.5.0.68 or greater.

This example applies to: Exchange Online | Office 365 | Hotmail.com | Live.com | MSN.com | Outlook.com | Passport.com

Chilkat PureBasic Downloads

PureBasic
IncludeFile "CkHttp.pb"
IncludeFile "CkStringBuilder.pb"
IncludeFile "CkJsonObject.pb"
IncludeFile "CkXml.pb"

Procedure ChilkatExample()

    success.i = 0

    ; This example requires the Chilkat API to have been previously unlocked.
    ; See Global Unlock Sample for sample code.

    http.i = CkHttp::ckCreate()
    If http.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    ; Use your previously obtained access token here:
    ; See the following examples for getting an access token:
    ;    Get Microsoft Graph OAuth2 Access Token (Azure AD v2.0 Endpoint).
    ;    Get Microsoft Graph OAuth2 Access Token (Azure AD Endpoint).
    ;    Refresh Access Token (Azure AD v2.0 Endpoint).
    ;    Refresh Access Token (Azure AD Endpoint).

    CkHttp::setCkAuthToken(http, "MICROSOFT_GRAPH_ACCESS_TOKEN")

    ; This example will iterate over the folders previously discovered by recursively traversing the Outlook folders
    ; as shown in this example:  Outlook Recursive Folder Traversal)

    ; The XML map produced by the recursive traversal looks like this:

    ; 	<?xml version="1.0" encoding="utf-8"?>
    ; 	<hashtable>
    ; 	<e><k>/Sent Items</k><v>AQMkADAwATM0MDAAMS1iNTcwLWI2NTEtMDACLTAwCgAuAAADsVyfxjDU406Ic4X7ill8xAEA5_vF7TKKdE6bGCRqXyl2PQAAAgEJAAAA</v></e>
    ; 	<e><k>/Inbox</k><v>AQMkADAwATM0MDAAMS1iNTcwLWI2NTEtMDACLTAwCgAuAAADsVyfxjDU406Ic4X7ill8xAEA5_vF7TKKdE6bGCRqXyl2PQAAAgEMAAAA</v></e>
    ; 	<e><k>/Junk Email</k><v>AQMkADAwATM0MDAAMS1iNTcwLWI2NTEtMDACLTAwCgAuAAADsVyfxjDU406Ic4X7ill8xAEA5_vF7TKKdE6bGCRqXyl2PQAAAgEiAAAA</v></e>
    ; 	<e><k>/Inbox/xyz</k><v>AQMkADAwATM0MDAAMS1iNTcwLWI2NTEtMDACLTAwCgAuAAADsVyfxjDU406Ic4X7ill8xAEA5_vF7TKKdE6bGCRqXyl2PQAAAL8huwEAAAA=</v></e>
    ; 	<e><k>/Inbox/abc/subFolderA/a</k><v>AQMkADAwATM0MDAAMS1iNTcwLWI2NTEtMDACLTAwCgAuAAADsVyfxjDU406Ic4X7ill8xAEA5_vF7TKKdE6bGCRqXyl2PQAAAL8huwIAAAA=</v></e>
    ; 	<e><k>/Inbox/abc</k><v>AQMkADAwATM0MDAAMS1iNTcwLWI2NTEtMDACLTAwCgAuAAADsVyfxjDU406Ic4X7ill8xAEA5_vF7TKKdE6bGCRqXyl2PQAAAL8huv8AAAA=</v></e>
    ; 	<e><k>/Outbox</k><v>AQMkADAwATM0MDAAMS1iNTcwLWI2NTEtMDACLTAwCgAuAAADsVyfxjDU406Ic4X7ill8xAEA5_vF7TKKdE6bGCRqXyl2PQAAAgELAAAA</v></e>
    ; 	<e><k>/Inbox/abc/subFolderA</k><v>AQMkADAwATM0MDAAMS1iNTcwLWI2NTEtMDACLTAwCgAuAAADsVyfxjDU406Ic4X7ill8xAEA5_vF7TKKdE6bGCRqXyl2PQAAAL8huwAAAQ==</v></e>
    ; 	<e><k>/Inbox/abc/subFolderB</k><v>AQMkADAwATM0MDAAMS1iNTcwLWI2NTEtMDACLTAwCgAuAAADsVyfxjDU406Ic4X7ill8xAEA5_vF7TKKdE6bGCRqXyl2PQAAAL8huwMAAAA=</v></e>
    ; 	<e><k>/Archive</k><v>AQMkADAwATM0MDAAMS1iNTcwLWI2NTEtMDACLTAwCgAuAAADsVyfxjDU406Ic4X7ill8xAEA5_vF7TKKdE6bGCRqXyl2PQAAAG8XunwAAAA=</v></e>
    ; 	<e><k>/Deleted Items</k><v>AQMkADAwATM0MDAAMS1iNTcwLWI2NTEtMDACLTAwCgAuAAADsVyfxjDU406Ic4X7ill8xAEA5_vF7TKKdE6bGCRqXyl2PQAAAgEKAAAA</v></e>
    ; 	<e><k>/Drafts</k><v>AQMkADAwATM0MDAAMS1iNTcwLWI2NTEtMDACLTAwCgAuAAADsVyfxjDU406Ic4X7ill8xAEA5_vF7TKKdE6bGCRqXyl2PQAAAgEPAAAA</v></e>
    ; 	</hashtable>

    ; We'll iterate over the folders, and search all folders beginning with "/Inbox" (effectively, we're recursively searching
    ; everything under Inbox)
    xmlMap.i = CkXml::ckCreate()
    If xmlMap.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    success = CkXml::ckLoadXmlFile(xmlMap,"qa_data/outlook/folderMap.xml")
    If success <> 1
        Debug "Failed to load XML folder map."
        CkHttp::ckDispose(http)
        CkXml::ckDispose(xmlMap)
        ProcedureReturn
    EndIf

    ; We're going to return just the message id, subject, and FROM name/address.
    CkHttp::ckSetUrlVar(http,"select","id,subject,from")

    ; Our search will be for emails with the word "sample" in the subject.
    CkHttp::ckSetUrlVar(http,"filter","contains(subject,'sample')")

    json.i = CkJsonObject::ckCreate()
    If json.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    CkJsonObject::setCkEmitCompact(json, 0)

    jsonCombined.i = CkJsonObject::ckCreate()
    If jsonCombined.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    CkJsonObject::setCkEmitCompact(jsonCombined, 0)

    sbResponse.i = CkStringBuilder::ckCreate()
    If sbResponse.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    sbPath.i = CkStringBuilder::ckCreate()
    If sbPath.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    numFolders.i = CkXml::ckNumChildren(xmlMap)
    i.i = 0
    j.i = 0
    k.i = 0
    While i < numFolders
        CkXml::setCkI(xmlMap, i)
        CkStringBuilder::ckSetString(sbPath,CkXml::ckGetChildContent(xmlMap,"e[i]|k"))

        If CkStringBuilder::ckStartsWith(sbPath,"/Inbox",1) = 1

            Debug "------------------------------------------------------------------"
            Debug "Searching " + CkStringBuilder::ckGetAsString(sbPath)

            ; Search this mail folder..
            CkHttp::ckSetUrlVar(http,"folder_id",CkXml::ckGetChildContent(xmlMap,"e[i]|v"))

            CkStringBuilder::ckClear(sbResponse)
            success = CkHttp::ckQuickGetSb(http,"https://graph.microsoft.com/v1.0/me/mailFolders/{$folder_id}/messages?$filter={$filter}&$select={$select}",sbResponse)
            If (success <> 1) AND (CkHttp::ckLastStatus(http) = 0)
                Debug CkHttp::ckLastErrorText(http)
                CkHttp::ckDispose(http)
                CkXml::ckDispose(xmlMap)
                CkJsonObject::ckDispose(json)
                CkJsonObject::ckDispose(jsonCombined)
                CkStringBuilder::ckDispose(sbResponse)
                CkStringBuilder::ckDispose(sbPath)
                ProcedureReturn
            EndIf

            CkJsonObject::ckLoadSb(json,sbResponse)

            If CkHttp::ckLastStatus(http) <> 200
                Debug "HTTP response status = " + Str(CkHttp::ckLastStatus(http))
                Debug CkJsonObject::ckEmit(json)
                Debug "Failed."
                CkHttp::ckDispose(http)
                CkXml::ckDispose(xmlMap)
                CkJsonObject::ckDispose(json)
                CkJsonObject::ckDispose(jsonCombined)
                CkStringBuilder::ckDispose(sbResponse)
                CkStringBuilder::ckDispose(sbPath)
                ProcedureReturn
            EndIf

            Debug CkJsonObject::ckEmit(json)

            ; Each mail folder search will return JSON with a value array, which is non-empty if any matching messages were found:

            ; 			{
            ; 			  "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#users('me')/mailFolders('AQMkADAwATM0MDAAMS1iNTcwLWI2NTEtMDACLTAwCgAuAAADsVyfxjDU406Ic4X7ill8xAEA5_vF7TKKdE6bGCRqXyl2PQAAAgEMAAAA')/messages(id,subject,from)",
            ; 			  "value": [
            ; 				Individual messages, if any, are listed here.
            ; 			  ]
            ; 			}

            numMessages.i = CkJsonObject::ckSizeOfArray(json,"value")
            j = 0
            While j < numMessages
                CkJsonObject::setCkJ(json, j)

                ; Add this message to the final result set.
                CkJsonObject::setCkK(jsonCombined, k)
                CkJsonObject::ckUpdateString(jsonCombined,"value[k].folderPath",CkStringBuilder::ckGetAsString(sbPath))
                CkJsonObject::ckUpdateString(jsonCombined,"value[k].id",CkJsonObject::ckStringOf(json,"value[j].id"))
                CkJsonObject::ckUpdateString(jsonCombined,"value[k].subject",CkJsonObject::ckStringOf(json,"value[j].subject"))
                CkJsonObject::ckUpdateString(jsonCombined,"value[k].from.emailAddress.name",CkJsonObject::ckStringOf(json,"value[j].from.emailAddress.name"))
                CkJsonObject::ckUpdateString(jsonCombined,"value[k].from.emailAddress.address",CkJsonObject::ckStringOf(json,"value[j].from.emailAddress.address"))
                k = k + 1

                j = j + 1
            Wend

        EndIf

        i = i + 1
    Wend

    ; Show the final combined JSON search result.
    Debug "------------------------------------------------------------------"
    Debug "Combined Search Results:"
    Debug CkJsonObject::ckEmit(jsonCombined)

    ; Sample output for the above program:

    ; ------------------------------------------------------------------
    ; Searching /Inbox
    ; {
    ;   "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#users('me')/mailFolders('AQMkADAwATM0MDAAMS1iNTcwLWI2NTEtMDACLTAwCgAuAAADsVyfxjDU406Ic4X7ill8xAEA5_vF7TKKdE6bGCRqXyl2PQAAAgEMAAAA')/messages(id,subject,from)",
    ;   "value": [
    ;     {
    ;       "@odata.etag": "W/\"CQAAABYAAADn68XtMop0TpsYJGpfKXY9AADOpwfr\"",
    ;       "id": "AQMkADAwATM0MDAAMS1iNTcwLWI2NTEtMDACLTAwCgBGAAADsVyfxjDU406Ic4X7ill8xAcA5_vF7TKKdE6bGCRqXyl2PQAAAgEMAAAA5_vF7TKKdE6bGCRqXyl2PQAAAM6Jj10AAAA=",
    ;       "subject": "A sample email with Amazon in the body",
    ;       "from": {
    ;         "emailAddress": {
    ;           "name": "Chilkat Software",
    ;           "address": "support@chilkatsoft.com"
    ;         }
    ;       }
    ;     }
    ;   ]
    ; }
    ; 
    ; ------------------------------------------------------------------
    ; Searching /Inbox/xyz
    ; {
    ;   "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#users('me')/mailFolders('AQMkADAwATM0MDAAMS1iNTcwLWI2NTEtMDACLTAwCgAuAAADsVyfxjDU406Ic4X7ill8xAEA5_vF7TKKdE6bGCRqXyl2PQAAAL8huwEAAAA%3D')/messages(id,subject,from)",
    ;   "value": [
    ;   ]
    ; }
    ; 
    ; ------------------------------------------------------------------
    ; Searching /Inbox/abc/subFolderA/a
    ; {
    ;   "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#users('me')/mailFolders('AQMkADAwATM0MDAAMS1iNTcwLWI2NTEtMDACLTAwCgAuAAADsVyfxjDU406Ic4X7ill8xAEA5_vF7TKKdE6bGCRqXyl2PQAAAL8huwIAAAA%3D')/messages(id,subject,from)",
    ;   "value": [
    ;     {
    ;       "@odata.etag": "W/\"CQAAABYAAADn68XtMop0TpsYJGpfKXY9AADOpzfb\"",
    ;       "id": "AQMkADAwATM0MDAAMS1iNTcwLWI2NTEtMDACLTAwCgBGAAADsVyfxjDU406Ic4X7ill8xAcA5_vF7TKKdE6bGCRqXyl2PQAAAL8huwIAAADn68XtMop0TpsYJGpfKXY9AAAAzombFQAAAA==",
    ;       "subject": "Sample email from admin@chilkat.io",
    ;       "from": {
    ;         "emailAddress": {
    ;           "name": "Chilkat Software",
    ;           "address": "admin@chilkat.io"
    ;         }
    ;       }
    ;     }
    ;   ]
    ; }
    ; 
    ; ------------------------------------------------------------------
    ; Searching /Inbox/abc
    ; {
    ;   "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#users('me')/mailFolders('AQMkADAwATM0MDAAMS1iNTcwLWI2NTEtMDACLTAwCgAuAAADsVyfxjDU406Ic4X7ill8xAEA5_vF7TKKdE6bGCRqXyl2PQAAAL8huv8AAAA%3D')/messages(id,subject,from)",
    ;   "value": [
    ;   ]
    ; }
    ; 
    ; ------------------------------------------------------------------
    ; Searching /Inbox/abc/subFolderA
    ; {
    ;   "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#users('me')/mailFolders('AQMkADAwATM0MDAAMS1iNTcwLWI2NTEtMDACLTAwCgAuAAADsVyfxjDU406Ic4X7ill8xAEA5_vF7TKKdE6bGCRqXyl2PQAAAL8huwAAAQ%3D%3D')/messages(id,subject,from)",
    ;   "value": [
    ;   ]
    ; }
    ; 
    ; ------------------------------------------------------------------
    ; Searching /Inbox/abc/subFolderB
    ; {
    ;   "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#users('me')/mailFolders('AQMkADAwATM0MDAAMS1iNTcwLWI2NTEtMDACLTAwCgAuAAADsVyfxjDU406Ic4X7ill8xAEA5_vF7TKKdE6bGCRqXyl2PQAAAL8huwMAAAA%3D')/messages(id,subject,from)",
    ;   "value": [
    ;   ]
    ; }
    ; 
    ; ------------------------------------------------------------------
    ; Combined Search Results:
    ; {
    ;   "value": [
    ;     {
    ;       "folderPath": "/Inbox",
    ;       "id": "AQMkADAwATM0MDAAMS1iNTcwLWI2NTEtMDACLTAwCgBGAAADsVyfxjDU406Ic4X7ill8xAcA5_vF7TKKdE6bGCRqXyl2PQAAAgEMAAAA5_vF7TKKdE6bGCRqXyl2PQAAAM6Jj10AAAA=",
    ;       "subject": "A sample email with Amazon in the body",
    ;       "from": {
    ;         "emailAddress": {
    ;           "name": "Chilkat Software",
    ;           "address": "support@chilkatsoft.com"
    ;         }
    ;       }
    ;     },
    ;     {
    ;       "folderPath": "/Inbox/abc/subFolderA/a",
    ;       "id": "AQMkADAwATM0MDAAMS1iNTcwLWI2NTEtMDACLTAwCgBGAAADsVyfxjDU406Ic4X7ill8xAcA5_vF7TKKdE6bGCRqXyl2PQAAAL8huwIAAADn68XtMop0TpsYJGpfKXY9AAAAzombFQAAAA==",
    ;       "subject": "Sample email from admin@chilkat.io",
    ;       "from": {
    ;         "emailAddress": {
    ;           "name": "Chilkat Software",
    ;           "address": "admin@chilkat.io"
    ;         }
    ;       }
    ;     }
    ;   ]
    ; }
    ; 


    CkHttp::ckDispose(http)
    CkXml::ckDispose(xmlMap)
    CkJsonObject::ckDispose(json)
    CkJsonObject::ckDispose(jsonCombined)
    CkStringBuilder::ckDispose(sbResponse)
    CkStringBuilder::ckDispose(sbPath)


    ProcedureReturn
EndProcedure