create_draft
Create draft emails in Gmail by specifying recipients, subject, and message content. Supports CC/BCC recipients and can associate drafts with existing email threads for organized communication management.
Instructions
Create a draft email in Gmail. Note the mechanics of the raw parameter.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| raw | No | The entire email message in base64url encoded RFC 2822 format, ignores params.to, cc, bcc, subject, body, includeBodyHtml if provided | |
| threadId | No | The thread ID to associate this draft with | |
| to | No | List of recipient email addresses | |
| cc | No | List of CC recipient email addresses | |
| bcc | No | List of BCC recipient email addresses | |
| subject | No | The subject of the email | |
| body | No | The body of the email | |
| includeBodyHtml | No | Whether to include the parsed HTML in the return for each body, excluded by default because they can be excessively large |
Implementation Reference
- src/index.ts:229-263 (registration)Registration of the 'create_draft' tool, including description, input schema with Zod, and inline handler function that creates a Gmail draft.server.tool("create_draft", "Create a draft email in Gmail. Note the mechanics of the raw parameter.", { raw: z.string().optional().describe("The entire email message in base64url encoded RFC 2822 format, ignores params.to, cc, bcc, subject, body, includeBodyHtml if provided"), threadId: z.string().optional().describe("The thread ID to associate this draft with"), to: z.array(z.string()).optional().describe("List of recipient email addresses"), cc: z.array(z.string()).optional().describe("List of CC recipient email addresses"), bcc: z.array(z.string()).optional().describe("List of BCC recipient email addresses"), subject: z.string().optional().describe("The subject of the email"), body: z.string().optional().describe("The body of the email"), includeBodyHtml: z.boolean().optional().describe("Whether to include the parsed HTML in the return for each body, excluded by default because they can be excessively large") }, async (params) => { return handleTool(config, async (gmail: gmail_v1.Gmail) => { let raw = params.raw if (!raw) raw = await constructRawMessage(gmail, params) const draftCreateParams: DraftCreateParams = { userId: 'me', requestBody: { message: { raw } } } if (params.threadId && draftCreateParams.requestBody?.message) { draftCreateParams.requestBody.message.threadId = params.threadId } const { data } = await gmail.users.drafts.create(draftCreateParams) if (data.message?.payload) { data.message.payload = processMessagePart( data.message.payload, params.includeBodyHtml ) } return formatResponse(data) }) } )
- src/index.ts:241-262 (handler)Inline handler function executing the create_draft tool logic: constructs raw message if not provided, creates draft via Gmail API, processes the payload, and formats the response.async (params) => { return handleTool(config, async (gmail: gmail_v1.Gmail) => { let raw = params.raw if (!raw) raw = await constructRawMessage(gmail, params) const draftCreateParams: DraftCreateParams = { userId: 'me', requestBody: { message: { raw } } } if (params.threadId && draftCreateParams.requestBody?.message) { draftCreateParams.requestBody.message.threadId = params.threadId } const { data } = await gmail.users.drafts.create(draftCreateParams) if (data.message?.payload) { data.message.payload = processMessagePart( data.message.payload, params.includeBodyHtml ) } return formatResponse(data) }) }
- src/index.ts:232-240 (schema)Input schema definition for the create_draft tool using Zod validators for parameters like raw, threadId, to, cc, etc.raw: z.string().optional().describe("The entire email message in base64url encoded RFC 2822 format, ignores params.to, cc, bcc, subject, body, includeBodyHtml if provided"), threadId: z.string().optional().describe("The thread ID to associate this draft with"), to: z.array(z.string()).optional().describe("List of recipient email addresses"), cc: z.array(z.string()).optional().describe("List of CC recipient email addresses"), bcc: z.array(z.string()).optional().describe("List of BCC recipient email addresses"), subject: z.string().optional().describe("The subject of the email"), body: z.string().optional().describe("The body of the email"), includeBodyHtml: z.boolean().optional().describe("Whether to include the parsed HTML in the return for each body, excluded by default because they can be excessively large") },
- src/index.ts:185-220 (helper)Helper function constructRawMessage that builds the base64url-encoded RFC 2822 raw email from params, handling threading, quoting previous content, and formatting.const constructRawMessage = async (gmail: gmail_v1.Gmail, params: NewMessage) => { let thread: Thread | null = null if (params.threadId) { const threadParams = { userId: 'me', id: params.threadId, format: 'full' } const { data } = await gmail.users.threads.get(threadParams) thread = data } const message = [] if (params.to?.length) message.push(`To: ${wrapTextBody(params.to.join(', '))}`) if (params.cc?.length) message.push(`Cc: ${wrapTextBody(params.cc.join(', '))}`) if (params.bcc?.length) message.push(`Bcc: ${wrapTextBody(params.bcc.join(', '))}`) if (thread) { message.push(...getThreadHeaders(thread).map(header => wrapTextBody(header))) } else if (params.subject) { message.push(`Subject: ${wrapTextBody(params.subject)}`) } else { message.push('Subject: (No Subject)') } message.push('Content-Type: text/plain; charset="UTF-8"') message.push('Content-Transfer-Encoding: quoted-printable') message.push('MIME-Version: 1.0') message.push('') if (params.body) message.push(wrapTextBody(params.body)) if (thread) { const quotedContent = getQuotedContent(thread) if (quotedContent) { message.push('') message.push(wrapTextBody(quotedContent)) } } return Buffer.from(message.join('\r\n')).toString('base64url').replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '') }
- src/index.ts:49-65 (helper)General helper handleTool used by create_draft to manage OAuth2 client creation, credential validation, Gmail API client setup, and error handling.const handleTool = async (queryConfig: Record<string, any> | undefined, apiCall: (gmail: gmail_v1.Gmail) => Promise<any>) => { try { const oauth2Client = queryConfig ? createOAuth2Client(queryConfig) : defaultOAuth2Client if (!oauth2Client) throw new Error('OAuth2 client could not be created, please check your credentials') const credentialsAreValid = await validateCredentials(oauth2Client) if (!credentialsAreValid) throw new Error('OAuth2 credentials are invalid, please re-authenticate') const gmailClient = queryConfig ? google.gmail({ version: 'v1', auth: oauth2Client }) : defaultGmailClient if (!gmailClient) throw new Error('Gmail client could not be created, please check your credentials') const result = await apiCall(gmailClient) return result } catch (error: any) { return `Tool execution failed: ${error.message}` } }