Sample code for 30+ languages & platforms
DataFlex

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 DataFlex Downloads

DataFlex
Use ChilkatAx-win32.pkg

Procedure Test
    Boolean iSuccess
    Handle hoHttp
    Handle hoXmlMap
    Handle hoJson
    Handle hoJsonCombined
    Variant vSbResponse
    Handle hoSbResponse
    Handle hoSbPath
    Integer iNumFolders
    Integer i
    Integer j
    Integer k
    Integer iNumMessages
    String sTemp1
    Integer iTemp1
    Boolean bTemp1

    Move False To iSuccess

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

    Get Create (RefClass(cComChilkatHttp)) To hoHttp
    If (Not(IsComObjectCreated(hoHttp))) Begin
        Send CreateComObject of hoHttp
    End

    // 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).

    Set ComAuthToken Of hoHttp To "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)
    Get Create (RefClass(cComChilkatXml)) To hoXmlMap
    If (Not(IsComObjectCreated(hoXmlMap))) Begin
        Send CreateComObject of hoXmlMap
    End
    Get ComLoadXmlFile Of hoXmlMap "qa_data/outlook/folderMap.xml" To iSuccess
    If (iSuccess <> True) Begin
        Showln "Failed to load XML folder map."
        Procedure_Return
    End

    // We're going to return just the message id, subject, and FROM name/address.
    Get ComSetUrlVar Of hoHttp "select" "id,subject,from" To iSuccess

    // Our search will be for emails with the word "sample" in the subject.
    Get ComSetUrlVar Of hoHttp "filter" "contains(subject,'sample')" To iSuccess

    Get Create (RefClass(cComChilkatJsonObject)) To hoJson
    If (Not(IsComObjectCreated(hoJson))) Begin
        Send CreateComObject of hoJson
    End
    Set ComEmitCompact Of hoJson To False

    Get Create (RefClass(cComChilkatJsonObject)) To hoJsonCombined
    If (Not(IsComObjectCreated(hoJsonCombined))) Begin
        Send CreateComObject of hoJsonCombined
    End
    Set ComEmitCompact Of hoJsonCombined To False

    Get Create (RefClass(cComChilkatStringBuilder)) To hoSbResponse
    If (Not(IsComObjectCreated(hoSbResponse))) Begin
        Send CreateComObject of hoSbResponse
    End
    Get Create (RefClass(cComChilkatStringBuilder)) To hoSbPath
    If (Not(IsComObjectCreated(hoSbPath))) Begin
        Send CreateComObject of hoSbPath
    End
    Get ComNumChildren Of hoXmlMap To iNumFolders
    Move 0 To i
    Move 0 To j
    Move 0 To k
    While (i < iNumFolders)
        Set ComI Of hoXmlMap To i
        Get ComGetChildContent Of hoXmlMap "e[i]|k" To sTemp1
        Get ComSetString Of hoSbPath sTemp1 To iSuccess

        Get ComStartsWith Of hoSbPath "/Inbox" True To bTemp1
        If (bTemp1 = True) Begin

            Showln "------------------------------------------------------------------"
            Get ComGetAsString Of hoSbPath To sTemp1
            Showln "Searching " sTemp1

            // Search this mail folder..
            Get ComGetChildContent Of hoXmlMap "e[i]|v" To sTemp1
            Get ComSetUrlVar Of hoHttp "folder_id" sTemp1 To iSuccess

            Send ComClear To hoSbResponse
            Get pvComObject of hoSbResponse to vSbResponse
            Get ComQuickGetSb Of hoHttp "https://graph.microsoft.com/v1.0/me/mailFolders/{$folder_id}/messages?$filter={$filter}&$select={$select}" vSbResponse To iSuccess
            Get ComLastStatus Of hoHttp To iTemp1
            If ((iSuccess <> True) And (iTemp1 = 0)) Begin
                Get ComLastErrorText Of hoHttp To sTemp1
                Showln sTemp1
                Procedure_Return
            End

            Get pvComObject of hoSbResponse to vSbResponse
            Get ComLoadSb Of hoJson vSbResponse To iSuccess

            Get ComLastStatus Of hoHttp To iTemp1
            If (iTemp1 <> 200) Begin
                Get ComLastStatus Of hoHttp To iTemp1
                Showln "HTTP response status = " iTemp1
                Get ComEmit Of hoJson To sTemp1
                Showln sTemp1
                Showln "Failed."
                Procedure_Return
            End

            Get ComEmit Of hoJson To sTemp1
            Showln sTemp1

            // 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.
            // 			  ]
            // 			}

            Get ComSizeOfArray Of hoJson "value" To iNumMessages
            Move 0 To j
            While (j < iNumMessages)
                Set ComJ Of hoJson To j

                // Add this message to the final result set.
                Set ComK Of hoJsonCombined To k
                Get ComGetAsString Of hoSbPath To sTemp1
                Get ComUpdateString Of hoJsonCombined "value[k].folderPath" sTemp1 To iSuccess
                Get ComStringOf Of hoJson "value[j].id" To sTemp1
                Get ComUpdateString Of hoJsonCombined "value[k].id" sTemp1 To iSuccess
                Get ComStringOf Of hoJson "value[j].subject" To sTemp1
                Get ComUpdateString Of hoJsonCombined "value[k].subject" sTemp1 To iSuccess
                Get ComStringOf Of hoJson "value[j].from.emailAddress.name" To sTemp1
                Get ComUpdateString Of hoJsonCombined "value[k].from.emailAddress.name" sTemp1 To iSuccess
                Get ComStringOf Of hoJson "value[j].from.emailAddress.address" To sTemp1
                Get ComUpdateString Of hoJsonCombined "value[k].from.emailAddress.address" sTemp1 To iSuccess
                Move (k + 1) To k

                Move (j + 1) To j
            Loop

        End

        Move (i + 1) To i
    Loop

    // Show the final combined JSON search result.
    Showln "------------------------------------------------------------------"
    Showln "Combined Search Results:"
    Get ComEmit Of hoJsonCombined To sTemp1
    Showln sTemp1

    // 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"
    //         }
    //       }
    //     }
    //   ]
    // }
    // 


End_Procedure