Email Drafts API
Create an Outlook draft email in the calling user's own connected mailbox. The draft is NOT sent — the user reviews it in Outlook and sends from there.
The calling user must have connected their Microsoft account at /settings/integrations. If they haven't, the endpoint returns 409 microsoft_not_connected with a link to the integration page.
Both surfaces (REST + MCP) accept the same request shape and produce a draft in the same Outlook Drafts folder.
POST /api/v1/email-drafts
Creates a draft in the calling user's Outlook Drafts folder. Auth: Authorization: Bearer avs_… or a JWT bearer token.
Request body
{
"to": ["[email protected]"],
"cc": ["[email protected]"],
"bcc": ["[email protected]"],
"subject": "Estimate ready for review",
"htmlBody": "<p>Hi Alice,</p><p>…</p>",
"attachments": [
{
"fileName": "estimate.pdf",
"contentType": "application/pdf",
"contentBase64": "JVBERi0xLjQK…"
}
],
"inReplyToMessageId": "AAMkAGI2…"
}
to, subject, htmlBody are required. All other fields are optional. When inReplyToMessageId is supplied the draft is created as a reply in the same Outlook conversation thread; the supplied to/cc/bcc overwrite Graph's reply defaults.
inReplyToMessageId must be a Microsoft Graph message id — the long URL-safe-base64 id field returned by GET /me/messages (typically starts with AAMk, around 140 characters). It is not the RFC 2822 Internet Message-Id (the <…@mail.gmail.com> value in raw email headers). Passing the wrong format returns graph_error with ErrorInvalidIdMalformed.
Response (200)
{
"draftId": "AAMkAGI2…",
"attachmentErrors": []
}
attachmentErrors only contains entries when an individual attachment failed; the draft itself still exists.
Error responses
| Status | Code | When |
|---|---|---|
| 400 | invalid_request | Missing to, malformed email address, missing attachment fields, etc. |
| 400 | too_many_recipients | Sum of to+cc+bcc exceeds 100. |
| 409 | microsoft_not_connected | User has not connected Microsoft. Body includes connectUrl. |
| 413 | payload_too_large | Total attachment bytes exceed 10 MB. |
| 429 | rate_limited | More than 20 drafts/min for this user. |
| 502 | graph_error | Microsoft Graph rejected the request. Body includes graphStatus and graphMessage. |
Limits
- Total recipients (to + cc + bcc): 100
- Attachments per draft: 25
- Total attachment bytes: 10 MB
- Subject length: 255 characters
- HTML body size: 5 MB
- Drafts per user per minute: 20
Example
curl -X POST https://app.avstackr.com/api/v1/email-drafts \
-H "Authorization: Bearer avs_…" \
-H "Content-Type: application/json" \
-d '{"to":["[email protected]"],"subject":"Follow-up","htmlBody":"<p>Hi,</p>"}'
MCP tool: create_email_draft
The same operation is exposed as an MCP tool. Field names use snake_case (html_body, in_reply_to_message_id, content_base64) instead of camelCase, and the response shape mirrors the REST envelope without HTTP wrapping:
{
"draft_id": "AAMkAGI2…",
"attachment_errors": []
}
Error responses use { "error": "<code>", "message": "…" } with the same code vocabulary as the REST endpoint. microsoft_not_connected additionally returns connect_url.
