draft/create
Save an email as a Gmail draft without sending, enabling human review and approval workflows before delivery.
When to Use
- Human review before send: Stage outbound emails for a manager or compliance officer to review and approve before the workflow sends them.
- Batch approval workflow: Prepare multiple templated emails as drafts, submit them for batch approval via a Human-in-the-Loop node, then send approved drafts.
- Support agent draft prep: Generate AI-drafted replies for support agents to review, edit, and send from their Gmail interface.
- Workflow checkpoint save: At a decision point in a complex workflow, save the partially composed email as a draft so the workflow can resume and complete it later.
- Scheduled send staging: Create drafts at workflow trigger time, then send them at a scheduled time using a ScheduledTrigger and Gmail API send-draft endpoint.
Configuration
Connection
| Field | Type | Description |
credentialId | Guid required | OAuth2 credential ID from BizFirst Credentials Manager. Requires gmail.send scope. |
Operation Fields
| Field | Type | Default | Description |
message | string required | — | Email body content. HTML or plain text depending on emailType. |
threadId | string optional | — | Thread ID to associate this draft as a reply. When set, the draft will be in-thread with the specified conversation. |
fromAlias | string optional | — | Send-as alias email address (must be configured in Gmail settings). Defaults to the authenticated account's primary address. |
subject | string optional | — | Email subject line. Required for new emails; optional for thread replies (inherits thread subject). |
emailType | enum optional | html | Content type: html or text. |
replyTo | string optional | — | Reply-To email address for the draft. |
ccList | string optional | — | Comma-separated CC email addresses. |
bccList | string optional | — | Comma-separated BCC email addresses. |
attachmentBinaryFields | string[] optional | — | Binary field names from upstream node outputs to attach to the draft. |
Sample Configuration
{
"nodeType": "Gmail",
"operation": "draft/create",
"credentialId": "a3f9d12b-44e1-4c89-b7d2-9f0a1e2b3c4d",
"subject": "Proposal for {{client.name}} — {{project.title}}",
"message": "<p>Dear {{client.name}},</p><p>Please find the project proposal attached.</p>",
"emailType": "html",
"ccList": "manager@bizfirstai.com",
"attachmentBinaryFields": ["proposalPdf"]
}
Validation Errors
| Error | Cause | Resolution |
MISSING_FIELD: message | Draft body is empty | Provide non-empty message content |
INVALID_CREDENTIAL | OAuth token expired or credential not found | Re-authenticate in BizFirst Credentials Manager |
THREAD_NOT_FOUND | Provided threadId does not exist | Verify the thread ID from the authenticated account |
INVALID_ALIAS | fromAlias is not configured in Gmail send-as settings | Configure the alias in Gmail Settings > Accounts before using |
Output
Success Port
| Field | Type | Description |
draftId | string | Gmail draft ID — use this to retrieve or delete the draft later |
messageId | string | The underlying message ID of the draft |
threadId | string | Thread ID the draft belongs to |
labelIds | string[] | Labels applied (typically ["DRAFT"]) |
status | string | success |
errorCode | string | Empty on success |
Error Port
On failure, routes to the error port with status: "error", errorCode, and errorMessage.
Sample Output
{
"draftId": "r9876543210abcdef",
"messageId": "18e4c3d2e1f0a9b8",
"threadId": "18e4c3d2e1f0a9b8",
"labelIds": ["DRAFT"],
"status": "success",
"errorCode": ""
}
Expression Reference
| Expression | Resolves To | Example Use |
{{client.name}} | Client name from CRM or upstream data | Subject and body personalization |
{{draftCreate.draftId}} | Draft ID from this node's output | Pass to approval node or draft/delete |
{{proposal.pdfBinary}} | PDF binary from document generator node | attachmentBinaryFields |
{{thread.id}} | Thread ID for in-thread draft reply | threadId field |
Node Policies & GuardRails
| Policy | Rule |
| Credential Storage | Store OAuth credentials in BizFirst Credentials Manager — never hardcode tokens in workflow configuration |
| Draft Lifecycle | Always delete drafts that are not sent — use draft/delete in the error path or after rejection to avoid inbox clutter |
| PII Protection | Do not log draft content in workflow execution history — drafts contain PII and pre-send content |
| Review Workflow | When using drafts for human review, implement a Human-in-the-Loop (HIL) approval node before the send step |
| Quota Management | Draft creation uses gmail.send quota — counts toward daily send limits even though the message is not delivered |
| Test Isolation | Test draft workflows against a dedicated Gmail test account to avoid creating unintended drafts in production inboxes |
Examples
Example 1: Proposal Draft for Manager Review
Generate a client proposal email, create it as a draft, then pause for manager approval before sending.
{
"nodeType": "Gmail",
"operation": "draft/create",
"credentialId": "a3f9d12b-44e1-4c89-b7d2-9f0a1e2b3c4d",
"subject": "Proposal — {{project.name}}",
"message": "{{proposalTemplate.html}}",
"emailType": "html",
"attachmentBinaryFields": ["proposalDocBinary"]
}
Example 2: AI-Generated Support Reply Draft
An AI agent generates a reply draft that a support agent reviews and sends from their Gmail inbox.
{
"nodeType": "Gmail",
"operation": "draft/create",
"credentialId": "a3f9d12b-44e1-4c89-b7d2-9f0a1e2b3c4d",
"threadId": "{{ticket.gmailThreadId}}",
"message": "{{aiAgent.generatedReplyHtml}}",
"emailType": "html"
}
Example 3: Scheduled Newsletter Draft
A workflow prepares newsletter drafts at month-end for a scheduled send on the first day of the next month.
{
"nodeType": "Gmail",
"operation": "draft/create",
"credentialId": "a3f9d12b-44e1-4c89-b7d2-9f0a1e2b3c4d",
"subject": "BizFirst Monthly Digest — {{$now | dateFormat:'MMMM YYYY'}}",
"message": "{{newsletter.compiledHtml}}",
"emailType": "html"
}