curl --request POST \
--url https://api.openworklabs.com/v1/capabilities/google-workspace/gmail-drafts \
--header 'Content-Type: application/json' \
--header 'x-api-key: <api-key>' \
--data '
{
"to": "<string>",
"subject": "<string>",
"body": "<string>",
"cc": "<string>",
"bcc": "<string>",
"timeZone": "<string>",
"threadId": "<string>",
"attachments": [
"<string>"
]
}
'import requests
url = "https://api.openworklabs.com/v1/capabilities/google-workspace/gmail-drafts"
payload = {
"to": "<string>",
"subject": "<string>",
"body": "<string>",
"cc": "<string>",
"bcc": "<string>",
"timeZone": "<string>",
"threadId": "<string>",
"attachments": ["<string>"]
}
headers = {
"x-api-key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'x-api-key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
to: '<string>',
subject: '<string>',
body: JSON.stringify('<string>'),
cc: '<string>',
bcc: '<string>',
timeZone: '<string>',
threadId: '<string>',
attachments: ['<string>']
})
};
fetch('https://api.openworklabs.com/v1/capabilities/google-workspace/gmail-drafts', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.openworklabs.com/v1/capabilities/google-workspace/gmail-drafts",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'to' => '<string>',
'subject' => '<string>',
'body' => '<string>',
'cc' => '<string>',
'bcc' => '<string>',
'timeZone' => '<string>',
'threadId' => '<string>',
'attachments' => [
'<string>'
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"x-api-key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.openworklabs.com/v1/capabilities/google-workspace/gmail-drafts"
payload := strings.NewReader("{\n \"to\": \"<string>\",\n \"subject\": \"<string>\",\n \"body\": \"<string>\",\n \"cc\": \"<string>\",\n \"bcc\": \"<string>\",\n \"timeZone\": \"<string>\",\n \"threadId\": \"<string>\",\n \"attachments\": [\n \"<string>\"\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-api-key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.openworklabs.com/v1/capabilities/google-workspace/gmail-drafts")
.header("x-api-key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"to\": \"<string>\",\n \"subject\": \"<string>\",\n \"body\": \"<string>\",\n \"cc\": \"<string>\",\n \"bcc\": \"<string>\",\n \"timeZone\": \"<string>\",\n \"threadId\": \"<string>\",\n \"attachments\": [\n \"<string>\"\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.openworklabs.com/v1/capabilities/google-workspace/gmail-drafts")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-api-key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"to\": \"<string>\",\n \"subject\": \"<string>\",\n \"body\": \"<string>\",\n \"cc\": \"<string>\",\n \"bcc\": \"<string>\",\n \"timeZone\": \"<string>\",\n \"threadId\": \"<string>\",\n \"attachments\": [\n \"<string>\"\n ]\n}"
response = http.request(request)
puts response.read_body{
"ok": true,
"draftId": "<string>",
"messageId": "<string>",
"draftUrl": "<string>",
"threadUrl": "<string>",
"to": "<string>",
"subject": "<string>",
"threadId": "<string>",
"quotedHistoryIncluded": true,
"attachments": [
{
"filename": "<string>",
"mimeType": "<string>",
"size": 4503599627370495
}
]
}{
"error": "invalid_request",
"details": [
{
"message": "<string>",
"path": [
"<string>"
]
}
],
"message": "<string>",
"capability": "<string>"
}{
"error": "unauthorized"
}{
"error": "needs_connection",
"message": "<string>"
}{
"ok": false,
"error": "file_input_requires_host",
"created": false,
"message": "Workspace attachments require a supporting OpenWork host. No draft was created. In the OpenWork desktop app, use the openwork_gmail_draft tool instead; otherwise do not retry without attachments."
}{
"error": "google_api_error",
"message": "<string>"
}Create a Gmail draft or threaded reply with optional workspace attachments
Creates a plain-text Gmail draft in the calling member own mailbox. Optional attachments are workspace paths, up to 10 files totaling at most 4 MiB, fulfilled outside model context by a supporting OpenWork host on direct execute_capability calls. Code Mode and other MCP hosts cannot fulfill attachments and create no draft. Set threadId for replies and forwards. Always share the returned draftUrl.
curl --request POST \
--url https://api.openworklabs.com/v1/capabilities/google-workspace/gmail-drafts \
--header 'Content-Type: application/json' \
--header 'x-api-key: <api-key>' \
--data '
{
"to": "<string>",
"subject": "<string>",
"body": "<string>",
"cc": "<string>",
"bcc": "<string>",
"timeZone": "<string>",
"threadId": "<string>",
"attachments": [
"<string>"
]
}
'import requests
url = "https://api.openworklabs.com/v1/capabilities/google-workspace/gmail-drafts"
payload = {
"to": "<string>",
"subject": "<string>",
"body": "<string>",
"cc": "<string>",
"bcc": "<string>",
"timeZone": "<string>",
"threadId": "<string>",
"attachments": ["<string>"]
}
headers = {
"x-api-key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'x-api-key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
to: '<string>',
subject: '<string>',
body: JSON.stringify('<string>'),
cc: '<string>',
bcc: '<string>',
timeZone: '<string>',
threadId: '<string>',
attachments: ['<string>']
})
};
fetch('https://api.openworklabs.com/v1/capabilities/google-workspace/gmail-drafts', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.openworklabs.com/v1/capabilities/google-workspace/gmail-drafts",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'to' => '<string>',
'subject' => '<string>',
'body' => '<string>',
'cc' => '<string>',
'bcc' => '<string>',
'timeZone' => '<string>',
'threadId' => '<string>',
'attachments' => [
'<string>'
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"x-api-key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.openworklabs.com/v1/capabilities/google-workspace/gmail-drafts"
payload := strings.NewReader("{\n \"to\": \"<string>\",\n \"subject\": \"<string>\",\n \"body\": \"<string>\",\n \"cc\": \"<string>\",\n \"bcc\": \"<string>\",\n \"timeZone\": \"<string>\",\n \"threadId\": \"<string>\",\n \"attachments\": [\n \"<string>\"\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-api-key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.openworklabs.com/v1/capabilities/google-workspace/gmail-drafts")
.header("x-api-key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"to\": \"<string>\",\n \"subject\": \"<string>\",\n \"body\": \"<string>\",\n \"cc\": \"<string>\",\n \"bcc\": \"<string>\",\n \"timeZone\": \"<string>\",\n \"threadId\": \"<string>\",\n \"attachments\": [\n \"<string>\"\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.openworklabs.com/v1/capabilities/google-workspace/gmail-drafts")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-api-key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"to\": \"<string>\",\n \"subject\": \"<string>\",\n \"body\": \"<string>\",\n \"cc\": \"<string>\",\n \"bcc\": \"<string>\",\n \"timeZone\": \"<string>\",\n \"threadId\": \"<string>\",\n \"attachments\": [\n \"<string>\"\n ]\n}"
response = http.request(request)
puts response.read_body{
"ok": true,
"draftId": "<string>",
"messageId": "<string>",
"draftUrl": "<string>",
"threadUrl": "<string>",
"to": "<string>",
"subject": "<string>",
"threadId": "<string>",
"quotedHistoryIncluded": true,
"attachments": [
{
"filename": "<string>",
"mimeType": "<string>",
"size": 4503599627370495
}
]
}{
"error": "invalid_request",
"details": [
{
"message": "<string>",
"path": [
"<string>"
]
}
],
"message": "<string>",
"capability": "<string>"
}{
"error": "unauthorized"
}{
"error": "needs_connection",
"message": "<string>"
}{
"ok": false,
"error": "file_input_requires_host",
"created": false,
"message": "Workspace attachments require a supporting OpenWork host. No draft was created. In the OpenWork desktop app, use the openwork_gmail_draft tool instead; otherwise do not retry without attachments."
}{
"error": "google_api_error",
"message": "<string>"
}Authorizations
Organization API key passed as the x-api-key header. The raw key is the header value; do not prefix it with Bearer.
Body
Recipient email address.
3 - 320Draft subject line. For replies or forwards, include threadId; subjects starting with Re: or Fwd: are rejected without threadId so the draft stays on the existing conversation.
1 - 500Draft body: plain prose or a safe Markdown subset (headings, bold, italic or italic, code, text [blocked], bare URLs, lists (-, *, 1.) with simple indented nesting, > block quotes, pipe tables, and fenced code). Links must use http, https, or mailto. Raw HTML is displayed as text, never executed. Separate paragraphs with blank lines; single line breaks, indentation, and repeated spaces are preserved. Do not hard-wrap prose. Put the closing (e.g. Thanks,) and sender name on separate lines with a real newline, never joined on one line. For threaded drafts, the server appends the quoted conversation automatically; do not include quoted history.
1 - 50000Optional comma-separated Cc email addresses.
3 - 1000Optional comma-separated Bcc email addresses.
3 - 1000User's IANA time zone (for example America/New_York). Pass the user's zone to format reply attribution like Gmail Web, including daylight saving time. When omitted, attribution keeps the original message Date header's offset, not the server's time zone.
1 - 100Gmail thread id to reply on. Required for replies and forwards; get it from the gmail-messages capability. When set, the draft is attached to that thread as a reply — keep the thread's subject (e.g. 'Re: …').
1 - 512Optional workspace file paths, 1 to 10 files totaling at most 4 MiB. File bytes stay outside model context. Requires a direct execute_capability call from a supporting OpenWork host; Code Mode and other MCP hosts are unsupported and create no draft. Do not retry without attachments.
1 - 10 elements1Response
Draft created.
Gmail URL for the ready-to-send draft. Always share draftUrl with the user so they can open the draft in Gmail for review and send.
Gmail URL for the conversation thread returned by Gmail for this draft.
True when quoted conversation history was included by the server or already present in the request body.
Show child attributes
Show child attributes
Was this page helpful?