> For clean Markdown of any page, append .md to the page URL. > For a complete documentation index, see https://docs.athenaintel.com/api-reference/tools/email/search/llms.txt. > For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.athenaintel.com/_mcp/server. # Search emails GET https://api.athenaintel.com/api/v0/tools/email/search Search the caller's connected Gmail or Outlook mailbox. Results come from the connected account the caller can access in their current workspace (the default account unless `catalog_id` names another). Unsent drafts are included and flagged with `is_draft`. Reference: https://docs.athenaintel.com/api-reference/tools/email/search ## Authentication - `X-API-KEY` header (required) — API Key authentication via header ## Request ### Query parameters - `query` (string, required) — Search query. Gmail operators (`from:`, `to:`, `subject:`, `has:attachment`, `newer_than:7d`, `-term`, …) are accepted for both providers; operators with no Outlook equivalent are dropped and reported in `ignored_operators`. Use `in:drafts` to search only unsent drafts. - `catalog_id` (string, optional, nullable) — Connected email account to use, as the catalog asset id returned by the Athena UI or the assets API. Defaults to the caller's default email account. An id that is not one of the caller's own connected accounts in the current workspace is a 404. - `limit` (integer, optional, default: 20) — Maximum number of results (1-50). ## Response ### 200 Successful Response - `catalog_id` (string, required) — The connected account that was searched. - `count` (integer, required) — Number of results returned. - `provider` (string, required) — Account provider as Athena reports it: `gmail` or `outlook` for accounts connected through the Integrations page; `google` or `microsoft365` for directly-connected accounts. - `query` (string, required) — The query as executed. - `draft_count` (integer, optional, default: 0) — How many of the results are unsent drafts. - `ignored_operators` (list of string, optional, nullable) — Gmail search operators that have no Outlook equivalent and were dropped from the query. Outlook accounts only. - `note` (string, optional, nullable) — Human-readable caveats about the results, when there are any. - `results` (list of EmailSearchResultOut, optional) — Matching messages, newest first. ## Errors ### 400 Bad Request Error The request cannot be carried out as written (`detail.code` = `EMAIL_REQUEST_REJECTED`): an invalid recipient address, or an account that is read-only in Athena (a Microsoft 365 shared mailbox). - `any` ### 403 Forbidden Error The caller has no workspace; the email toolkit is disabled in this environment (`detail.code` = `ENVIRONMENT_FEATURE_DISABLED`); the tool is disabled for the workspace in its Tool Registry (`TOOL_NOT_ENABLED`); or the connected account is denied by its provider (for example a Microsoft 365 or Google Workspace connection that has not been granted write permission) or its connector is not enabled for the workspace (`EMAIL_PROVIDER_ACCESS_DENIED`, `EMAIL_CONNECTOR_NOT_ENABLED`). - `any` ### 404 Not Found Error No Gmail or Outlook account is connected (`detail.code` = `EMAIL_ACCOUNT_NOT_CONNECTED`); the requested `catalog_id` is not an account the caller can use (`EMAIL_ACCOUNT_NOT_FOUND`); or the provider has no such message or event (`PROVIDER_RESOURCE_NOT_FOUND`). - `any` ### 422 Unprocessable Entity Error Validation Error - `detail` (list of ValidationError, optional) ### 429 Too Many Requests Error The connected account is temporarily rate-limited by its provider (`detail.code` = `EMAIL_PROVIDER_RATE_LIMITED`). `Retry-After` is set when the provider communicated a wait; retrying earlier extends the lockout. - `any` ### 502 Bad Gateway Error The email provider rejected or failed the request (`detail.code` = `EMAIL_PROVIDER_ERROR`); `detail.message` carries the provider's status and `detail.provider_status` its code. - `any` ## Types ### EmailSearchResultOut One message matched by an email search. - `id` (string, required) — Provider message id (Gmail message id, or Microsoft Graph message id for Outlook). This — never an Athena asset id — is what `reply_to_message_id` accepts. - `conversation_id` (string, optional, nullable) — Microsoft Graph conversation id. Outlook accounts only. - `date` (string, optional, default: ) — Sent or received timestamp, in the provider's format. - `draft_id` (string, optional, nullable) — Provider draft id, when the provider exposes one for a draft. - `from` (string, optional, default: ) — Sender, as the provider reports it. - `is_draft` (boolean, optional, default: false) — True when the message is an unsent draft sitting in the mailbox. Drafts are never sent or received mail and cannot be replied to. - `snippet` (string, optional, default: ) — Short plain-text preview. - `subject` (string, optional, default: ) — Subject line. - `thread_id` (string, optional, nullable) — Gmail thread id. Gmail accounts only. - `to` (string, optional, default: ) — Recipients, comma-separated as the provider reports them. ### ValidationError - `loc` (list of ValidationErrorLocItems, required) - `msg` (string, required) - `type` (string, required) - `ctx` (ValidationErrorCtx, optional) - `input` (any, optional) ### ValidationErrorLocItems ### ValidationErrorCtx ## Examples **Response** ```json { "catalog_id": "string", "count": 1, "provider": "string", "query": "string", "draft_count": 0, "ignored_operators": [ "string" ], "note": "string", "results": [ { "id": "string", "conversation_id": "string", "date": "", "draft_id": "string", "from": "", "is_draft": false, "snippet": "", "subject": "", "thread_id": "string", "to": "" } ] } ``` **SDK Code** ```python import requests url = "https://api.athenaintel.com/api/v0/tools/email/search" querystring = {"query":"query"} headers = {"X-API-KEY": ""} response = requests.get(url, headers=headers, params=querystring) print(response.json()) ``` ```javascript const url = 'https://api.athenaintel.com/api/v0/tools/email/search?query=query'; const options = {method: 'GET', headers: {'X-API-KEY': ''}}; try { const response = await fetch(url, options); const data = await response.json(); console.log(data); } catch (error) { console.error(error); } ``` ```go package main import ( "fmt" "net/http" "io" ) func main() { url := "https://api.athenaintel.com/api/v0/tools/email/search?query=query" req, _ := http.NewRequest("GET", url, nil) req.Header.Add("X-API-KEY", "") res, _ := http.DefaultClient.Do(req) defer res.Body.Close() body, _ := io.ReadAll(res.Body) fmt.Println(res) fmt.Println(string(body)) } ``` ```ruby require 'uri' require 'net/http' url = URI("https://api.athenaintel.com/api/v0/tools/email/search?query=query") http = Net::HTTP.new(url.host, url.port) http.use_ssl = true request = Net::HTTP::Get.new(url) request["X-API-KEY"] = '' response = http.request(request) puts response.read_body ``` ```java import com.mashape.unirest.http.HttpResponse; import com.mashape.unirest.http.Unirest; HttpResponse response = Unirest.get("https://api.athenaintel.com/api/v0/tools/email/search?query=query") .header("X-API-KEY", "") .asString(); ``` ```php request('GET', 'https://api.athenaintel.com/api/v0/tools/email/search?query=query', [ 'headers' => [ 'X-API-KEY' => '', ], ]); echo $response->getBody(); ``` ```csharp using RestSharp; var client = new RestClient("https://api.athenaintel.com/api/v0/tools/email/search?query=query"); var request = new RestRequest(Method.GET); request.AddHeader("X-API-KEY", ""); IRestResponse response = client.Execute(request); ``` ```swift import Foundation let headers = ["X-API-KEY": ""] let request = NSMutableURLRequest(url: NSURL(string: "https://api.athenaintel.com/api/v0/tools/email/search?query=query")! as URL, cachePolicy: .useProtocolCachePolicy, timeoutInterval: 10.0) request.httpMethod = "GET" request.allHTTPHeaderFields = headers let session = URLSession.shared let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in if (error != nil) { print(error as Any) } else { let httpResponse = response as? HTTPURLResponse print(httpResponse) } }) dataTask.resume() ```