PageSourceSearch

https://learn.emailengine.app/assets/js/59d898bc.3a8b06fe.js

js emailengine.app collected 2026-09-25 20:15:55 UTC 18,518 bytes, 1 lines download raw bytes

1"use strict";(globalThis.webpackChunkemailengine_temp=globalThis.webpackChunkemailengine_temp||[]).push([[7391],{1832(e,n,s){s.r(n),s.d(n,{assets:()=>h,contentTitle:()=>t,default:()=>l,frontMatter:()=>a,metadata:()=>r,toc:()=>o});const r=JSON.parse('{"id":"sending/threading/provider-support","title":"Provider-Specific Threading","description":"Which backends give EmailEngine a native thread ID, what it looks like, and which of them can search a whole thread in one request","source":"@site/docs/sending/threading/provider-support.md","sourceDirName":"sending/threading","slug":"/sending/threading/provider-support","permalink":"/docs/sending/threading/provider-support","draft":false,"unlisted":false,"tags":[],"version":"current","sidebarPosition":2,"frontMatter":{"title":"Provider-Specific Threading","sidebar_position":2,"description":"Which backends give EmailEngine a native thread ID, what it looks like, and which of them can search a whole thread in one request"},"sidebar":"docsSidebar","previous":{"title":"Threading Overview","permalink":"/docs/sending/threading/overview"},"next":{"title":"Searching Thread Messages","permalink":"/docs/sending/threading/searching-threads"}}');var i=s(74848),d=s(28453);const a={title:"Provider-Specific Threading",sidebar_position:2,description:"Which backends give EmailEngine a native thread ID, what it looks like, and which of them can search a whole thread in one request"},t="Provider-Specific Threading Support",h={},o=[{value:"Gmail / Google Workspace",id:"gmail--google-workspace",level:2},{value:"Native Thread Support",id:"native-thread-support",level:3},{value:"Example Response",id:"example-response",level:3},{value:"Microsoft 365 / Outlook",id:"microsoft-365--outlook",level:2},{value:"Native Thread Support",id:"native-thread-support-1",level:3},{value:"Example Response",id:"example-response-1",level:3},{value:"Yahoo / AOL / Verizon",id:"yahoo--aol--verizon",level:2},{value:"Example Response",id:"example-response-2",level:3},{value:"Other IMAP Providers",id:"other-imap-providers",level:2},{value:"Provider Comparison Table",id:"provider-comparison-table",level:2},{value:"Choosing the Backend",id:"choosing-the-backend",level:2},{value:"Gmail accounts",id:"gmail-accounts",level:3},{value:"Microsoft 365 / Outlook accounts",id:"microsoft-365--outlook-accounts",level:3},{value:"Yahoo / AOL / Verizon",id:"yahoo--aol--verizon-1",level:3},{value:"Other providers",id:"other-providers",level:3},{value:"Migration Considerations",id:"migration-considerations",level:2},{value:"Switching a Microsoft 365 account from IMAP to the Graph API",id:"switching-a-microsoft-365-account-from-imap-to-the-graph-api",level:3},{value:"Testing Thread Support",id:"testing-thread-support",level:2},{value:"Check the account type",id:"check-the-account-type",level:3},{value:"Test thread ID availability",id:"test-thread-id-availability",level:3},{value:"See Also",id:"see-also",level:2}];function c(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,d.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.header,{children:(0,i.jsx)(n.h1,{id:"provider-specific-threading-support",children:"Provider-Specific Threading Support"})}),"\n",(0,i.jsxs)(n.p,{children:["Whether a message carries a ",(0,i.jsx)(n.code,{children:"threadId"}),", and whether a whole thread can be fetched in one request, depends on the backend the account uses. This page lists what each one provides."]}),"\n",(0,i.jsx)(n.h2,{id:"gmail--google-workspace",children:"Gmail / Google Workspace"}),"\n",(0,i.jsx)(n.p,{children:"Both Gmail backends assign a thread ID to every message."}),"\n",(0,i.jsx)(n.h3,{id:"native-thread-support",children:"Native Thread Support"}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.strong,{children:"Backends"}),":"]}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["IMAP with OAuth2: ",(0,i.jsx)(n.code,{children:"threadId"})," from the ",(0,i.jsx)(n.code,{children:"X-GM-THRID"})," attribute of Gmail's ",(0,i.jsx)(n.code,{children:"X-GM-EXT-1"})," IMAP extension"]}),"\n",(0,i.jsxs)(n.li,{children:["Gmail API: ",(0,i.jsx)(n.code,{children:"threadId"})," from the API"]}),"\n"]}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.strong,{children:"Characteristics"}),":"]}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["Thread ID format: long numeric string, for example ",(0,i.jsx)(n.code,{children:'"1759349012996310407"'}),", the same value over either backend"]}
1),"\n",(0,i.jsx)(n.li,{children:"Availability: webhooks, message listings, message details, search results"}),"\n",(0,i.jsxs)(n.li,{children:["The ",(0,i.jsx)(n.code,{children:"\\All"})," folder is available for cross-folder thread search"]}),"\n",(0,i.jsxs)(n.li,{children:["On the Gmail API, ",(0,i.jsx)(n.code,{children:"reference.threadId"})," on submit attaches an outgoing message to a thread directly; see ",(0,i.jsx)(n.a,{href:"/docs/sending/threading/sending-threaded#using-the-reference-api",children:"Sending threaded messages"})]}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"example-response",children:"Example Response"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:'curl "https://emailengine.example.com/v1/account/gmail/messages?path=INBOX" \\\n  -H "Authorization: Bearer <token>"\n'})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-json",children:'{\n  "messages": [\n    {\n      "id": "AAABkPHBeR0",\n      "threadId": "1759349012996310407",\n      "subject": "Project discussion",\n      "from": {\n        "address": "[email protected]"\n      }\n    }\n  ]\n}\n'})}),"\n",(0,i.jsx)(n.h2,{id:"microsoft-365--outlook",children:"Microsoft 365 / Outlook"}),"\n",(0,i.jsx)(n.p,{children:"Which backend the account uses decides everything here."}),"\n",(0,i.jsx)(n.h3,{id:"native-thread-support-1",children:"Native Thread Support"}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.strong,{children:"Backends"}),":"]}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["Microsoft Graph API: ",(0,i.jsx)(n.code,{children:"threadId"})," is the message's Graph ",(0,i.jsx)(n.code,{children:"conversationId"})]}),"\n",(0,i.jsx)(n.li,{children:"IMAP with OAuth2: no thread ID"}),"\n"]}),"\n",(0,i.jsxs)(n.p,{children:["Only an account added with the ",(0,i.jsx)(n.strong,{children:"Microsoft Graph API"})," backend has a ",(0,i.jsx)(n.code,{children:"threadId"}),". A Microsoft 365 account added over ",(0,i.jsx)(n.strong,{children:"IMAP with OAuth2"})," talks to Microsoft's IMAP server, which implements neither ",(0,i.jsx)(n.code,{children:"OBJECTID"})," nor a Gmail-style extension, so it behaves like any other IMAP account: threads have to be built from headers."]}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.strong,{children:"Characteristics (Graph API)"}),":"]}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["Thread ID format: Graph conversation ID, for example ",(0,i.jsx)(n.code,{children:'"AAQkAGI2THY2ZjRhLTVjNzgtNDMxYS05YTBmLTJiN2M4ZDkxZTQyMwAQAF3xTx0nRUxOhKcvLZQ9r1M="'})]}),"\n",(0,i.jsx)(n.li,{children:"Availability: webhooks, message listings, message details, search results"}),"\n",(0,i.jsxs)(n.li,{children:["The ",(0,i.jsx)(n.code,{children:"\\All"})," folder is available for cross-folder thread search; a ",(0,i.jsx)(n.code,{children:"threadId"})," search on it filters on ",(0,i.jsx)(n.code,{children:"conversationId"})]}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"example-response-1",children:"Example Response"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-json",children:'{\n  "messages": [\n    {\n      "id": "AAMkAGI2THY2ZjRhLTVjNzgtNDMxYS05YTBmLTJiN2M4ZDkxZTQyMwBGAAAAAABBUq8CzXaBTKl9k7lJ0hJ7BwCXKmSHhLBFTr0AAA==",\n      "threadId": "AAQkAGI2THY2ZjRhLTVjNzgtNDMxYS05YTBmLTJiN2M4ZDkxZTQyMwAQAF3xTx0nRUxOhKcvLZQ9r1M=",\n      "subject": "Meeting tomorrow",\n      "from": {\n        "address": "[email protected]"\n      }\n    }\n  ]\n}\n'})}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.strong,{children:"Backend comparison"}),":"]}),"\n",(0,i.jsxs)(n.table,{children:[(0,i.jsx)(n.thead,{children:(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.th,{children:"Backend"}),(0,i.jsx)(n.th,{children:"Threading"}),(0,i.jsx)(n.th,{children:"\\All folder"})]})}),(0,i.jsxs)(n.tbody,{children:[(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:"Microsoft Graph API"}),(0,i.jsx)(n.td,{children:"Native"}),(0,i.jsx)(n.td,{children:"Yes"})]}),(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:"IMAP with OAuth2"}),(0,i.jsx)(n.td,{children:"Manual only"}),(0,i.jsx)(n.td,{children:"No"})]})]})]}),"\n",(0,i.jsx)(n.h2,{id:"yahoo--aol--verizon",children:"Yahoo / AOL / Verizon"}),"\n",(0,i.jsxs)(n.p,{children:["Yahoo, AOL, and Verizon IMAP servers implement the ",(0,i.jsx)(n.code,{children:"OBJECTID"})," extension (RFC 8474), and EmailEngine passes its ",(0,i.jsx)(n.code,{children:"THREADID"})," attribute on as ",(0,i.jsx)(n.code,{children:"threadId"}),"."]}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.strong,{children:"Characteristics"}),":"]}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["Thread ID format: short numeric string, for example ",(0,i.jsx)(n.code,{children:'"501"'})]}),"\n",(0,i.jsx)(n.li,{children:"Availability: webhooks, message listings, message details, search results"}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsxs)(n.strong,{children:["No ",(0,i.jsx)(n.code,{children:"\\All"})," folder"]}),": search each folder separately and merge the results, as shown in ",(0,i.jsx)(n.a,{href:"/docs/sending/threading/searching-threads#folder-by-folder-search",children:"Searching threads"})]}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"example-response-2",children:"Example Response"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-json",children:'{\n  "messages": [\n    {\n      "id": "AAAAKAAACKM",\n      "threadId": "501",\n      "subject": "Question about your service",\n      "from": {\n        "address": "[email protected]"\n      }\n    }\n  ]\n}\n'})}),"\n",(0,i.jsxs)(n.p,{children:["The same applies to any other IMAP server that advertises ",(0,i.jsx)(n.code,{children:"OBJECTID"}),": the thread ID is available, the ",(0,i.jsx)(n.code,{children:"\\All"})," folder is not."]}),"\n",(0,i.jsx)(n.h2,{id:"other-imap-providers",children:"Other IMAP Providers"}),"\n",(0,i.jsxs)(n.p,{children:["An IMAP server without ",(0,i.jsx)(n.code,{children:"OBJECTID"})," or ",(0,i.jsx)(n.code,{children:"X-GM-EXT-1"})," gives EmailEngine no thread identifier."]}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.strong,{children:"Characteristics"}),":"]}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["No ",(0,i.jsx)(n.code,{children:"threadId"})," property in any response"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"threadId"})," cannot be used as a search term"]}),"\n",(0,i.jsxs)(n.li,{children:["No ",(0,i.jsx)(n.code,{children:"\\All"})," folder"]}),"\n",(0,i.jsxs)(n.li,{children:["Threads are reconstructed client-side from ",(0,i.jsx)(n.code,{children:"Message-ID"}),", ",(0,i.jsx)(n.code,{children:"In-Reply-To"}),", and ",(0,i.jsx)(n.code,{children:"References"})]}),"\n"]}),"\n",(0,i.jsxs)(n.p,{children:["The procedure is: search the relevant folders by ",(0,i.jsx)(n.code,{children:"subject"}),", fetch the candidates, and group them on their headers. ",(0,i.jsx)(n.a,{href:"/docs/sending/threading/searching-threads#building-threads-manually",children:"Building threads manually"})," has the code."]}),"\n",(0,i.jsx)(n.h2,{id:"provider-comparison-table",children:"Provider Comparison Table"}),"\n",(0,i.jsxs)(n.table,{children:[(0,i.jsx)(n.thead,{children:(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.th,{children:"Provider"}),(0,i.jsx)(n.th,{children:"Backend"}),(0,i.jsx)(n.th,{children:"Native threading"}),(0,i.jsx)(n.th,{children:"Thread ID format"}),(0,i.jsx)(n.th,{children:"\\All folder"})]})}),(0,i.jsxs)(n.tbody,{children:[(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:"Gmail"}),(0,i.jsx)(n.td,{children:"IMAP + OAuth2"}),(0,i.jsx)(n.td,{children:"Yes"}),(0,i.jsx)(n.td,{children:"Long numeric"}),(0,i.jsx)(n.td,{children:"Yes"})]}),(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:"Gmail"}),(0,i.jsx)(n.td,{children:"Gmail API"}),(0,i.jsx)(n.td,{children:"Yes"}),(0,i.jsx)(n.td,{children:"Long numeric"}),(0,i.jsx)(n.td,{children:"Yes"})]}),(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:"Microsoft 365"}),(0,i.jsx)(n.td,{children:"Graph API"}),(0,i.jsx)(n.td,{children:"Yes"}),(0,i.jsx)(n.td,{children:"Graph conversation ID"}),(0,i.jsx)(n.td,{children:"Yes"})]}),(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:"Microsoft 365"}),(0,i.jsx)(n.td,{children:"IMAP + OAuth2"}),(0,i.jsx)(n.td,{children:"No"}),(0,i.jsx)(n.td,{children:"N/A (manual only)"}),(0,i.jsx)(n.td,{children:"No"})]}),(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:"Yahoo/AOL/Verizon"}),(0,i.jsx)(n.td,{children:"IMAP"}),(0,i.jsx)(n.td,{children:"Yes (OBJECTID)"}),(0,i.jsx)(n.td,{children:"Short numeric"}),(0,i.jsx)(n.td,{children:"No"})]}),(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:"Other IMAP"}),(0,i.jsx)(n.td,{children:"IMAP"}),(0,i.jsx)(n.td,{children:"No"}),(0,i.jsx)(n.td,{children:"N/A (manual only)"}),(0,i.jsx)(n.td,{children:"No"})]})]})]}),"\n",(0,i.jsx)(n.h2,{id:"choosing-the-backend",children:"Choosing the Backend"}),"\n",(0,i.jsx)(n.h3,{id:"gmail-accounts",children:"Gmail accounts"}),"\n",(0,i.jsxs)(n.p,{children:["Either backend gives you thread IDs and the ",(0,i.jsx)(n.code,{children:"\\All"})," folder. Choose between IMAP and the Gmail API on other grounds; see ",(0,i.jsx)(n.a,{href:"/docs/accounts/gmail/gmail-imap",children:"Gmail accounts"}),"."]}),"\n",(0,i.jsx)(n.h3,{id:"microsoft-365--outlook-accounts",children:"Microsoft 365 / Outlook accounts"}),"\n",(0,i.jsxs)(n.p,{children:["Use the ",(0,i.jsx)(n.strong,{children:"Microsoft Graph API"})," backend if you need thread IDs or cross-folder thread search. Over IMAP, neither is available."]}),"\n",(0,i.jsx)(n.h3,{id:"yahoo--aol--verizon-1",children:"Yahoo / AOL / Verizon"}),"\n",(0,i.jsx)(n.p,{children:"Standard IMAP. Thread IDs are available; plan for one search per folder."}),"\n",(0,i.jsx)(n.h3,{id:"other-providers",children:"Other providers"}),"\n",(0,i.jsx)(n.p,{children:"Plan for client-side threading: building thread relationships from headers, searching several folders, and keeping any thread state in your own application."}),"\n",(0,i.jsx)(n.h2,{id:"migration-considerations",children:"Migration Considerations"}),"\n",(0,i.jsx)(n.h3,{id:"switching-a-microsoft-365-account-from-imap-to-the-graph-api",children:"Switching a Microsoft 365 account from IMAP to the Graph API"}),"\n",(0,i.jsxs)(n.ol,{children:["\n",(0,i.jsx)(n.li,{children:"The account has to be re-authorized through an OAuth2 application with the Graph API base scopes; the IMAP grant does not carry over"}),"\n",(0,i.jsxs)(n.li,{children:["Messages get new EmailEngine message IDs, and ",(0,i.jsx)(n.code,{children:"threadId"})," becomes available"]}),"\n",(0,i.jsx)(n.li,{children:"Update your application to use the Graph conversation IDs"}),"\n",(0,i.jsx)(n.li,{children:"Any thread mapping you built from headers stays valid only as long as you keep the headers it was built from"}),"\n"]}),"\n",(0,i.jsx)(n.h2,{id:"testing-thread-support",children:"Testing Thread Supp
1ort"}),"\n",(0,i.jsx)(n.h3,{id:"check-the-account-type",children:"Check the account type"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:'curl "https://emailengine.example.com/v1/account/example" \\\n  -H "Authorization: Bearer <token>"\n'})}),"\n",(0,i.jsxs)(n.p,{children:["Two fields of the ",(0,i.jsx)(n.a,{href:"/docs/api/get-v-1-account-account",children:"account response"})," settle it together:"]}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"type"})," names the provider: ",(0,i.jsx)(n.code,{children:"gmail"})," for a Google account, ",(0,i.jsx)(n.code,{children:"outlook"})," for a Microsoft account, ",(0,i.jsx)(n.code,{children:"imap"})," for a password-authenticated IMAP account"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"baseScopes"})," says which backend an OAuth2 account uses: ",(0,i.jsx)(n.code,{children:"imap"})," for IMAP with OAuth2, ",(0,i.jsx)(n.code,{children:"api"})," for the Gmail or Graph API. It is present only for OAuth2 accounts, and defaults to ",(0,i.jsx)(n.code,{children:"imap"})," when the ",(0,i.jsx)(n.a,{href:"/docs/api/get-v-1-oauth-2-app",children:"OAuth2 application"})," does not set it"]}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"test-thread-id-availability",children:"Test thread ID availability"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:'curl "https://emailengine.example.com/v1/account/example/messages?path=INBOX" \\\n  -H "Authorization: Bearer <token>"\n'})}),"\n",(0,i.jsxs)(n.p,{children:["If the entries have no ",(0,i.jsx)(n.code,{children:"threadId"}),", the backend assigns none, and threads have to be built from headers."]}),"\n",(0,i.jsx)(n.h2,{id:"see-also",children:"See Also"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.a,{href:"/docs/sending/threading/overview",children:"Threading overview"})," - The headers and IDs this table is about"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.a,{href:"/docs/sending/threading/searching-threads",children:"Searching threads"})," - The search strategy each provider needs"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.a,{href:"/docs/accounts",children:"Account types"})," - Choosing the backend that gives you native threading"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.a,{href:"/docs/receiving/searching",children:"Searching messages"})," - What else the search endpoint can filter on"]}),"\n"]})]})}function l(e={}){const{wrapper:n}={...(0,d.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(c,{...e})}):c(e)}},28453(e,n,s){s.d(n,{R:()=>a,x:()=>t});var r=s(96540);const i={},d=r.createContext(i);function a(e){const n=r.useContext(d);return r.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function t(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:a(e.components),r.createElement(d.Provider,{value:n},e.children)}}}]);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.