> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.athenaintel.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.athenaintel.com/_mcp/server.

# Get one email message

GET https://api.athenaintel.com/api/v0/tools/email/messages/{message_id}

Read one message from the caller's connected Gmail or Outlook mailbox.

Returns its headers and its body as plain text, so an agent can keep the
whole email (in a CRM timeline, for example) rather than the search
snippet. Read-only; attachments are not returned.

Reference: https://docs.athenaintel.com/api-reference/tools/email/get-message

## Authentication

- `X-API-KEY` header (required) — API Key authentication via header

## Request

### Path parameters

- `message_id` (string, required) — Provider message id, as `GET /tools/email/search` returns it in `results[].id`.

### Query parameters

- `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.

## Response

### 200

Successful Response

- `catalog_id` (string, required) — The connected account the message was read from.
- `id` (string, required) — Provider message id, as `GET /tools/email/search` returns it and `reply_to_message_id` accepts.
- `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.
- `body_text` (string, optional, default: ) — The message body as plain text, HTML converted. At most 50,000 characters; see `truncated`.
- `cc` (string, optional, default: ) — Cc recipients, comma-separated as the provider reports them.
- `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.
- `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.
- `truncated` (boolean, optional, default: false) — True when `body_text` was cut to its maximum length.

## 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`); the Tool Registry requires approval for it, which an API call cannot give (`tool_requires_approval`); 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

### ValidationError

- `loc` (list of ValidationErrorLocItems, required)
- `msg` (string, required)
- `type` (string, required)
- `ctx` (ValidationErrorCtx, optional)
- `input` (any, optional)

### ValidationErrorLocItems

- string
- integer

### ValidationErrorCtx

## Examples

**Response**

```json
{
  "catalog_id": "asset_1d3f9b2e-6a4c-4c1b-9f0e-2a7b8c9d0e1f",
  "id": "18f2a7c3b9d4e5f6",
  "provider": "gmail",
  "body_text": "Hi,\n\nThe Q3 numbers are attached.\n\nAda",
  "cc": "",
  "date": "Mon, 7 Sep 2026 10:00:00 +0000",
  "from": "Ada Lovelace <ada@example.com>",
  "is_draft": false,
  "subject": "Q3 forecast",
  "thread_id": "18f2a7c3b9d4e5f6",
  "to": "me@example.com",
  "truncated": false
}
```

**SDK Code**

```python
import requests

url = "https://api.athenaintel.com/api/v0/tools/email/messages/message_id"

headers = {"X-API-KEY": "<apiKey>"}

response = requests.get(url, headers=headers)

print(response.json())
```

```javascript
const url = 'https://api.athenaintel.com/api/v0/tools/email/messages/message_id';
const options = {method: 'GET', headers: {'X-API-KEY': '<apiKey>'}};

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/messages/message_id"

	req, _ := http.NewRequest("GET", url, nil)

	req.Header.Add("X-API-KEY", "<apiKey>")

	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/messages/message_id")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Get.new(url)
request["X-API-KEY"] = '<apiKey>'

response = http.request(request)
puts response.read_body
```

```java
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.get("https://api.athenaintel.com/api/v0/tools/email/messages/message_id")
  .header("X-API-KEY", "<apiKey>")
  .asString();
```

```php
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('GET', 'https://api.athenaintel.com/api/v0/tools/email/messages/message_id', [
  'headers' => [
    'X-API-KEY' => '<apiKey>',
  ],
]);

echo $response->getBody();
```

```csharp
using RestSharp;

var client = new RestClient("https://api.athenaintel.com/api/v0/tools/email/messages/message_id");
var request = new RestRequest(Method.GET);
request.AddHeader("X-API-KEY", "<apiKey>");
IRestResponse response = client.Execute(request);
```

```swift
import Foundation

let headers = ["X-API-KEY": "<apiKey>"]

let request = NSMutableURLRequest(url: NSURL(string: "https://api.athenaintel.com/api/v0/tools/email/messages/message_id")! 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()
```