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

# Create an email draft

POST https://api.athenaintel.com/api/v0/tools/email/draft
Content-Type: application/json

Save a draft in the caller's connected Gmail or Outlook account.

Nothing is sent. The draft appears in the account's Drafts folder, where it
is reviewed, edited and sent from the mail client — that review step is why
drafting is available here while sending is not. Set `reply_to_message_id`
to thread the draft as a reply.

Reference: https://docs.athenaintel.com/api-reference/tools/email/create-draft

## Authentication

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

## Request

### Body (application/json)

This endpoint expects an EmailDraftRequestIn.

- `body` (string, required) — Body content. HTML is supported; plain-text newlines become line breaks. Do not write a signature into it — the account's signature is appended automatically (see `include_signature`).
- `subject` (string, required) — Subject line.
- `to` (list of string, required) — Recipient email addresses.
- `bcc` (list of string, optional, nullable) — BCC recipients.
- `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.
- `cc` (list of string, optional, nullable) — CC recipients.
- `include_signature` (boolean, optional, nullable) — Optional: Whether to append the sending account's own signature at the end of the body. Leave unset to follow the user's saved preference for this account (which distinguishes new messages from replies) — that is almost always the right choice. Set false only when the user asks for no signature. Never write a signature into the body yourself: the real one is read from the account and appended automatically.
- `reply_to_message_id` (string, optional, nullable) — Provider message id (from `GET /tools/email/search`) to reply to, so the draft is threaded under that message. Outlook rejects an id it cannot find (404). Gmail saves the draft *unthreaded* when the referenced message cannot be read, and `reply_to_message_id` in the response tells you which happened.

## Response

### 200

Successful Response

- `catalog_id` (string, required) — The connected account the draft is in.
- `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.
- `success` (boolean, required) — Whether the draft was saved.
- `draft_id` (string, optional, nullable) — Provider draft id. Open, edit, or send it in the mail client.
- `email_address` (string, optional, nullable) — The address the draft will be sent from.
- `message` (string, optional, nullable) — Human-readable outcome, when the provider reports one.
- `message_id` (string, optional, nullable) — Provider message id backing the draft. Gmail accounts only.
- `reply_to_message_id` (string, optional, nullable) — The message this draft replies to, when it is a reply.
- `tracking_id` (string, optional, nullable) — Athena email-tracking id, when tracking is enabled on the account.

## 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

**Request**

```json
{
  "body": "Hi Ada,<br><br>Attached below is the Q3 forecast summary.",
  "subject": "Q3 forecast",
  "to": [
    "ada@example.com"
  ],
  "cc": [
    "grace@example.com"
  ]
}
```

**Response**

```json
{
  "catalog_id": "string",
  "provider": "string",
  "success": true,
  "draft_id": "string",
  "email_address": "string",
  "message": "string",
  "message_id": "string",
  "reply_to_message_id": "string",
  "tracking_id": "string"
}
```

**SDK Code**

```python
import requests

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

payload = {
    "body": "Hi Ada,<br><br>Attached below is the Q3 forecast summary.",
    "subject": "Q3 forecast",
    "to": ["ada@example.com"],
    "cc": ["grace@example.com"]
}
headers = {
    "X-API-KEY": "<apiKey>",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.json())
```

```javascript
const url = 'https://api.athenaintel.com/api/v0/tools/email/draft';
const options = {
  method: 'POST',
  headers: {'X-API-KEY': '<apiKey>', 'Content-Type': 'application/json'},
  body: '{"body":"Hi Ada,<br><br>Attached below is the Q3 forecast summary.","subject":"Q3 forecast","to":["ada@example.com"],"cc":["grace@example.com"]}'
};

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"
	"strings"
	"net/http"
	"io"
)

func main() {

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

	payload := strings.NewReader("{\n  \"body\": \"Hi Ada,<br><br>Attached below is the Q3 forecast summary.\",\n  \"subject\": \"Q3 forecast\",\n  \"to\": [\n    \"ada@example.com\"\n  ],\n  \"cc\": [\n    \"grace@example.com\"\n  ]\n}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("X-API-KEY", "<apiKey>")
	req.Header.Add("Content-Type", "application/json")

	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/draft")

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

request = Net::HTTP::Post.new(url)
request["X-API-KEY"] = '<apiKey>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"body\": \"Hi Ada,<br><br>Attached below is the Q3 forecast summary.\",\n  \"subject\": \"Q3 forecast\",\n  \"to\": [\n    \"ada@example.com\"\n  ],\n  \"cc\": [\n    \"grace@example.com\"\n  ]\n}"

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.post("https://api.athenaintel.com/api/v0/tools/email/draft")
  .header("X-API-KEY", "<apiKey>")
  .header("Content-Type", "application/json")
  .body("{\n  \"body\": \"Hi Ada,<br><br>Attached below is the Q3 forecast summary.\",\n  \"subject\": \"Q3 forecast\",\n  \"to\": [\n    \"ada@example.com\"\n  ],\n  \"cc\": [\n    \"grace@example.com\"\n  ]\n}")
  .asString();
```

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

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://api.athenaintel.com/api/v0/tools/email/draft', [
  'body' => '{
  "body": "Hi Ada,<br><br>Attached below is the Q3 forecast summary.",
  "subject": "Q3 forecast",
  "to": [
    "ada@example.com"
  ],
  "cc": [
    "grace@example.com"
  ]
}',
  'headers' => [
    'Content-Type' => 'application/json',
    'X-API-KEY' => '<apiKey>',
  ],
]);

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

```csharp
using RestSharp;

var client = new RestClient("https://api.athenaintel.com/api/v0/tools/email/draft");
var request = new RestRequest(Method.POST);
request.AddHeader("X-API-KEY", "<apiKey>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"body\": \"Hi Ada,<br><br>Attached below is the Q3 forecast summary.\",\n  \"subject\": \"Q3 forecast\",\n  \"to\": [\n    \"ada@example.com\"\n  ],\n  \"cc\": [\n    \"grace@example.com\"\n  ]\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift
import Foundation

let headers = [
  "X-API-KEY": "<apiKey>",
  "Content-Type": "application/json"
]
let parameters = [
  "body": "Hi Ada,<br><br>Attached below is the Q3 forecast summary.",
  "subject": "Q3 forecast",
  "to": ["ada@example.com"],
  "cc": ["grace@example.com"]
] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://api.athenaintel.com/api/v0/tools/email/draft")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

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()
```