{ "kind": "open-flow-workflow", "version": 1, "name": "Gmail To-Do Label to Google Tasks", "content": { "modelVersion": 14, "document": { "bindings": {}, "graph": { "nodes": { "n_0fe62b6c07d03321": { "name": "New To-Do Gmail messages", "kind": "poll", "config": { "labelNamesOrIds": { "kind": "value", "value": [ "To-Do" ] }, "readStatus": { "kind": "value", "value": "All" }, "search": { "kind": "value", "value": "" }, "sender": { "kind": "value", "value": "" }, "includeDrafts": { "kind": "value", "value": false }, "includeSpamAndTrash": { "kind": "value", "value": false }, "maxMessagesPerPoll": { "kind": "value", "value": 50 } }, "definition": { "configInputs": [ { "description": "Only trigger on messages carrying all of these labels, referenced by name or ID.", "jsonSchema": { "type": "array", "items": { "type": "string", "minLength": 1 } }, "nullable": false, "handle": "labelNamesOrIds", "value": [] }, { "jsonSchema": { "type": "string", "enum": [ "Read", "Unread", "All" ] }, "nullable": false, "handle": "readStatus", "value": "All" }, { "description": "Gmail search-syntax query the message must match.", "jsonSchema": { "type": "string" }, "nullable": false, "handle": "search", "value": "" }, { "description": "Only trigger on messages whose sender matches this address or name.", "jsonSchema": { "type": "string" }, "nullable": false, "handle": "sender", "value": "" }, { "collapsed": true, "group": "Advanced settings" }, { "description": "Also trigger on draft messages.", "jsonSchema": { "type": "boolean" }, "nullable": false, "handle": "includeDrafts", "value": false }, { "description": "Also trigger on messages in SPAM and TRASH.", "jsonSchema": { "type": "boolean" }, "nullable": false, "handle": "includeSpamAndTrash", "value": false }, { "jsonSchema": { "type": "integer", "minimum": 1, "maximum": 100 }, "nullable": false, "handle": "maxMessagesPerPoll", "value": 25 } ], "definitionVersion": 2, "description": "Polls the Gmail mailbox and triggers when a new message is received.", "displayName": "New Message Received", "key": "gmail.on_message_received", "name": "on_message_received", "outputs": [ { "jsonSchema": { "type": "array", "items": { "type": "object", "properties": { "historyId": { "type": [ "string", "null" ] }, "labelIds": { "type": "array", "items": { "type": "string" } }, "messageId": { "type": "string" }, "messageTimestamp": { "type": "string" }, "sender": { "type": "string" }, "subject": { "type": "string" }, "threadId": { "type": "string" }, "to": { "type": "string" } }, "additionalProperties": false, "required": [ "messageId", "threadId", "historyId", "labelIds", "subject", "sender", "to", "messageTimestamp" ] } }, "nullable": false, "handle": "events" } ], "provider": "gmail", "type": "poll" }, "pollTimes": [ { "type": "every", "unit": "minute", "value": 1 } ] }, "n_c17c02b5a40ecf27": { "inputs": { "events": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_0fe62b6c07d03321", "output": "events" } ] }, "previousState": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_c17c02b5a40ecf27", "output": "state" } ] } }, "name": "Choose the next message", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "array", "items": { "type": "object", "properties": { "historyId": { "type": [ "string", "null" ] }, "labelIds": { "type": "array", "items": { "type": "string" } }, "messageId": { "type": "string" }, "messageTimestamp": { "type": "string" }, "sender": { "type": "string" }, "subject": { "type": "string" }, "threadId": { "type": "string" }, "to": { "type": "string" } }, "additionalProperties": false, "required": [ "messageId", "threadId", "historyId", "labelIds", "subject", "sender", "to", "messageTimestamp" ] } }, "nullable": false, "handle": "events" }, { "jsonSchema": { "type": "object", "additionalProperties": true }, "nullable": true, "handle": "previousState" } ], "outputs": [ { "jsonSchema": { "type": "object", "additionalProperties": true }, "nullable": false, "handle": "state" }, { "jsonSchema": { "type": "boolean" }, "nullable": false, "handle": "more" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "messageId" }, { "jsonSchema": { "type": "integer", "minimum": 0 }, "nullable": false, "handle": "count" } ], "name": "Choose the next message", "moduleId": "n_9a841fc59583a6a4", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } }, "n_3b7de7239c5d3546": { "inputs": {}, "name": "Any messages remaining", "kind": "condition", "matchMode": "first", "cases": [ { "output": "more", "groups": [ { "expressions": [ { "left": { "kind": "source", "source": { "kind": "node", "nodeId": "n_c17c02b5a40ecf27", "output": "more" } }, "operator": "==", "right": { "kind": "value", "value": true } } ] } ] } ] }, "n_bf8c98e2efe256f5": { "inputs": { "messageId": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_c17c02b5a40ecf27", "output": "messageId" } ] }, "format": { "kind": "value", "value": "full" } }, "name": "Fetch the message snippet", "kind": "task", "task": { "inputs": [ { "description": "Gmail message ID.", "jsonSchema": { "type": "string", "description": "Gmail message ID." }, "nullable": false, "handle": "messageId" }, { "description": "Gmail response format to request.", "jsonSchema": { "type": "string", "enum": [ "minimal", "full", "raw", "metadata" ], "description": "Gmail response format to request." }, "nullable": true, "handle": "format", "value": null } ], "outputs": [ { "description": "The message history ID.", "jsonSchema": { "type": "string", "description": "The message history ID." }, "nullable": true, "handle": "historyId" }, { "description": "The internal timestamp in milliseconds.", "jsonSchema": { "type": "string", "description": "The internal timestamp in milliseconds." }, "nullable": true, "handle": "internalDate" }, { "description": "The estimated message size in bytes.", "jsonSchema": { "type": "integer", "description": "The estimated message size in bytes." }, "nullable": true, "handle": "sizeEstimate" }, { "description": "The message snippet.", "jsonSchema": { "type": "string", "description": "The message snippet." }, "nullable": true, "handle": "snippet" }, { "description": "Gmail message ID.", "jsonSchema": { "type": "string", "description": "Gmail message ID." }, "nullable": false, "handle": "messageId" }, { "description": "Gmail thread ID.", "jsonSchema": { "type": "string", "description": "Gmail thread ID." }, "nullable": false, "handle": "threadId" }, { "description": "Label IDs applied to the message.", "jsonSchema": { "type": "array", "items": { "type": "string", "description": "An array item." }, "description": "Label IDs applied to the message." }, "nullable": false, "handle": "labelIds" }, { "description": "Normalized message subject line.", "jsonSchema": { "type": "string", "description": "Normalized message subject line." }, "nullable": false, "handle": "subject" }, { "description": "Normalized sender value.", "jsonSchema": { "type": "string", "description": "Normalized sender value." }, "nullable": false, "handle": "sender" }, { "description": "Normalized To header value.", "jsonSchema": { "type": "string", "description": "Normalized To header value." }, "nullable": false, "handle": "to" }, { "description": "Short preview of the message subject and body.", "jsonSchema": { "type": "object", "properties": { "subject": { "type": "string", "description": "Preview subject extracted from the message." }, "body": { "type": "string", "description": "Preview body text extracted from the message." } }, "required": [ "subject", "body" ], "additionalProperties": false, "description": "Short preview of the message subject and body." }, "nullable": false, "handle": "preview" }, { "description": "Raw Gmail payload object, or null when it was not included.", "jsonSchema": { "type": [ "object", "null" ], "additionalProperties": { "description": "A record value." }, "description": "Raw Gmail payload object, or null when it was not included." }, "nullable": true, "handle": "payload" }, { "description": "Best-effort plain-text representation of the message body.", "jsonSchema": { "type": "string", "description": "Best-effort plain-text representation of the message body." }, "nullable": false, "handle": "messageText" }, { "description": "Normalized attachment summaries.", "jsonSchema": { "type": "array", "items": { "type": "object", "properties": { "attachmentId": { "type": [ "string", "null" ], "description": "Attachment ID, or null when Gmail inlines the body." }, "filename": { "type": "string", "description": "Attachment filename." }, "mimeType": { "type": "string", "description": "Attachment MIME type." }, "size": { "type": "integer", "description": "Attachment size in bytes." }, "partId": { "type": [ "string", "null" ], "description": "Gmail MIME part ID, when supplied." }, "contentId": { "type": [ "string", "null" ], "description": "Bare Content-ID, when supplied." }, "disposition": { "type": [ "string", "null" ], "enum": [ "inline", "attachment", null ], "description": "Content-Disposition, when supplied." } }, "required": [ "attachmentId", "filename", "mimeType", "size", "partId", "contentId", "disposition" ], "additionalProperties": false, "description": "Schema for gmailAttachmentSchema." }, "description": "Normalized attachment summaries." }, "nullable": false, "handle": "attachmentList" }, { "description": "Message timestamp returned by Gmail.", "jsonSchema": { "type": "string", "description": "Message timestamp returned by Gmail." }, "nullable": false, "handle": "messageTimestamp" }, { "description": "Raw RFC 2822 message content when Gmail returns it.", "jsonSchema": { "type": "string", "description": "Raw RFC 2822 message content when Gmail returns it." }, "nullable": true, "handle": "raw" } ], "name": "Fetch the message snippet", "executor": { "kind": "connector", "action": "gmail.fetch_message_by_message_id" } } }, "n_993383d8ea632e03": { "inputs": { "expectedId": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_c17c02b5a40ecf27", "output": "messageId" } ] }, "messageId": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_bf8c98e2efe256f5", "output": "messageId" } ] }, "subject": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_bf8c98e2efe256f5", "output": "subject" } ] }, "snippet": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_bf8c98e2efe256f5", "output": "snippet" } ] }, "tasklistId": { "kind": "value", "value": "YOUR_TASK_LIST_ID" } }, "name": "Prepare the Google Task", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "expectedId" }, { "jsonSchema": { "type": "string", "description": "Gmail message ID." }, "nullable": false, "handle": "messageId" }, { "jsonSchema": { "type": "string", "description": "Normalized message subject line." }, "nullable": false, "handle": "subject" }, { "jsonSchema": { "type": "string", "description": "The message snippet." }, "nullable": true, "handle": "snippet" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "tasklistId" } ], "outputs": [ { "jsonSchema": { "type": "string", "description": "Task title." }, "nullable": true, "handle": "title" }, { "jsonSchema": { "type": "string", "description": "Plain-text task notes." }, "nullable": true, "handle": "notes" }, { "jsonSchema": { "type": "string", "format": "date-time", "description": "Task due timestamp in RFC 3339 format." }, "nullable": true, "handle": "due" }, { "jsonSchema": { "type": "string", "minLength": 1, "description": "Google Tasks task list ID. Use @default for the primary list when supported." }, "nullable": true, "handle": "tasklistId" } ], "name": "Prepare the Google Task", "moduleId": "n_080a62ee0f3f4cf8", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } }, "n_7ed4d304c9b401c5": { "inputs": { "tasklistId": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_993383d8ea632e03", "output": "tasklistId" } ] }, "title": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_993383d8ea632e03", "output": "title" } ] }, "notes": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_993383d8ea632e03", "output": "notes" } ] }, "due": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_993383d8ea632e03", "output": "due" } ] } }, "name": "Create the task", "kind": "task", "task": { "inputs": [ { "description": "Google Tasks task list ID. Use @default for the primary list when supported.", "jsonSchema": { "type": "string", "minLength": 1, "description": "Google Tasks task list ID. Use @default for the primary list when supported." }, "nullable": true, "handle": "tasklistId", "value": null }, { "description": "Task resource ID to send in the request body.", "jsonSchema": { "type": "string", "description": "Task resource ID to send in the request body." }, "nullable": true, "handle": "id", "value": null }, { "description": "Entity tag to send in the request body.", "jsonSchema": { "type": "string", "description": "Entity tag to send in the request body." }, "nullable": true, "handle": "etag", "value": null }, { "description": "Task title.", "jsonSchema": { "type": "string", "description": "Task title." }, "nullable": true, "handle": "title", "value": null }, { "description": "Plain-text task notes.", "jsonSchema": { "type": "string", "description": "Plain-text task notes." }, "nullable": true, "handle": "notes", "value": null }, { "description": "Task status.", "jsonSchema": { "type": "string", "enum": [ "needsAction", "completed" ], "description": "Task status." }, "nullable": true, "handle": "status", "value": null }, { "description": "Task due timestamp in RFC 3339 format.", "jsonSchema": { "type": "string", "format": "date-time", "description": "Task due timestamp in RFC 3339 format." }, "nullable": true, "handle": "due", "value": null }, { "description": "Completion timestamp in RFC 3339 format when the task is completed.", "jsonSchema": { "type": "string", "format": "date-time", "description": "Completion timestamp in RFC 3339 format when the task is completed." }, "nullable": true, "handle": "completed", "value": null }, { "description": "Whether the task is marked as deleted.", "jsonSchema": { "type": "boolean", "description": "Whether the task is marked as deleted." }, "nullable": true, "handle": "deleted", "value": null }, { "description": "Parent task ID.", "jsonSchema": { "type": "string", "description": "Parent task ID." }, "nullable": true, "handle": "taskParent", "value": null }, { "description": "Previous sibling task ID.", "jsonSchema": { "type": "string", "description": "Previous sibling task ID." }, "nullable": true, "handle": "taskPrevious", "value": null } ], "outputs": [ { "description": "Created task.", "jsonSchema": { "type": "object", "properties": { "id": { "type": "string", "description": "Google Tasks task ID." }, "kind": { "type": "string", "description": "Google Tasks resource kind." }, "etag": { "type": [ "string", "null" ], "description": "Entity tag for the task resource." }, "title": { "type": [ "string", "null" ], "description": "Task title." }, "notes": { "type": [ "string", "null" ], "description": "Task notes." }, "status": { "type": [ "string", "null" ], "enum": [ "needsAction", "completed", null ], "description": "Task status." }, "parent": { "type": [ "string", "null" ], "description": "Parent task ID when this task is a subtask." }, "position": { "type": [ "string", "null" ], "description": "Lexicographic position token among sibling tasks." }, "due": { "type": [ "string", "null" ], "description": "Task due timestamp in RFC 3339 format." }, "completed": { "type": [ "string", "null" ], "description": "Timestamp when the task was completed, in RFC 3339 format." }, "deleted": { "type": "boolean", "description": "Whether the task is marked as deleted." }, "hidden": { "type": "boolean", "description": "Whether the task is hidden from the default Google Tasks view." }, "updated": { "type": [ "string", "null" ], "description": "Last update time for the task, in RFC 3339 format." }, "selfLink": { "type": [ "string", "null" ], "description": "API URL for the task resource." }, "webViewLink": { "type": [ "string", "null" ], "description": "Google Tasks web URL for the task." }, "links": { "type": "array", "items": { "type": "object", "properties": { "type": { "type": "string", "description": "Type of linked resource." }, "link": { "type": "string", "description": "Absolute URL or URI for the linked resource." }, "description": { "type": "string", "description": "Human-readable description of the link." } }, "required": [ "type", "link" ], "additionalProperties": false, "description": "A link attached to a Google Task." }, "description": "Links attached to the task." }, "assignmentInfo": { "type": [ "object", "null" ], "properties": { "surfaceType": { "type": "string", "enum": [ "CONTEXT_TYPE_UNSPECIFIED", "GMAIL", "DOCUMENT", "SPACE" ], "description": "Type of surface where the task was assigned." }, "linkToTask": { "type": "string", "description": "Absolute link to the source assignment surface." }, "spaceInfo": { "type": "object", "properties": { "space": { "type": "string", "description": "Google Chat space resource name." } }, "additionalProperties": false, "description": "Google Chat space information for assigned tasks." }, "driveResourceInfo": { "type": "object", "properties": { "driveFileId": { "type": "string", "description": "Google Drive file ID for the source document." }, "resourceKey": { "type": "string", "description": "Google Drive resource key for the source document." } }, "additionalProperties": false, "description": "Google Drive file information for assigned tasks." } }, "additionalProperties": false, "description": "Assignment metadata for tasks created from other Google surfaces." } }, "required": [ "id", "kind", "etag", "title", "notes", "status", "parent", "position", "due", "completed", "deleted", "hidden", "updated", "selfLink", "webViewLink", "links", "assignmentInfo" ], "additionalProperties": false, "description": "Created task." }, "nullable": false, "handle": "task" } ], "name": "Create the task", "executor": { "kind": "connector", "action": "googletasks.insert_task" } } }, "n_1ac2661eb9cf06d4": { "name": "Messages processed", "kind": "outputs", "outputDefs": [ { "jsonSchema": { "type": "integer", "minimum": 0 }, "nullable": false, "handle": "count" } ], "outputMappings": { "count": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_c17c02b5a40ecf27", "output": "count" } ] } } } }, "edges": [ { "source": "n_0fe62b6c07d03321", "target": "n_c17c02b5a40ecf27" }, { "source": "n_c17c02b5a40ecf27", "target": "n_3b7de7239c5d3546" }, { "source": "n_3b7de7239c5d3546", "target": "n_bf8c98e2efe256f5", "sourceHandle": "more" }, { "source": "n_3b7de7239c5d3546", "target": "n_1ac2661eb9cf06d4", "sourceHandle": "otherwise" }, { "source": "n_bf8c98e2efe256f5", "target": "n_993383d8ea632e03" }, { "source": "n_993383d8ea632e03", "target": "n_7ed4d304c9b401c5" }, { "source": "n_7ed4d304c9b401c5", "target": "n_c17c02b5a40ecf27" } ] } }, "modules": { "n_9a841fc59583a6a4": { "name": "Choose the next message", "imports": [], "source": "export default function gmailTaskProgress({ events, previousState }) {\n if (!Array.isArray(events) || events.length > 50) throw new Error('Invalid Gmail poll page');\n for (const e of events) if (!e || typeof e.messageId !== 'string' || !e.messageId) throw new Error('Invalid Gmail event');\n let index = 0;\n if (previousState != null) {\n if (!Number.isInteger(previousState.index) || previousState.index < 0 || previousState.index >= events.length) throw new Error('Invalid Gmail page progress');\n index = previousState.index + 1;\n }\n return { state: { index }, more: index < events.length, messageId: events[index]?.messageId ?? '', count: index };\n}\n" }, "n_080a62ee0f3f4cf8": { "name": "Prepare the Google Task", "imports": [], "source": "export default function gmailTaskPlan({ expectedId, messageId, subject, snippet, tasklistId }) {\n if (expectedId !== messageId) throw new Error('Fetched a different Gmail message');\n if (typeof subject !== 'string' || !subject.trim()) throw new Error('The message needs a subject for the task title');\n if (snippet != null && typeof snippet !== 'string') throw new Error('Invalid Gmail snippet');\n if (typeof tasklistId !== 'string' || !tasklistId.trim() || tasklistId === 'YOUR_TASK_LIST_ID') throw new Error('Set the Google Tasks list ID');\n const now = new Date();\n const tomorrow = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate() + 1)).toISOString();\n return { title: subject, notes: snippet ?? '', due: tomorrow, tasklistId };\n}\n" } } }, "presentation": { "designer": { "version": 1, "flow": { "direction": "vertical" } } } }