{ "kind": "open-flow-workflow", "version": 1, "name": "Gmail Message Snippets to Google Sheets", "content": { "modelVersion": 14, "document": { "bindings": {}, "graph": { "nodes": { "n_b5c9b81a3be65b67": { "name": "New Gmail messages each minute", "kind": "poll", "config": { "labelNamesOrIds": { "kind": "value", "value": [] }, "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_1cd1af7756035155": { "inputs": { "events": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_b5c9b81a3be65b67", "output": "events" } ] }, "previousState": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_1cd1af7756035155", "output": "state" } ] }, "row": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_160a99282514a829", "output": "row" } ] } }, "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" }, { "jsonSchema": { "type": "object", "additionalProperties": true }, "nullable": true, "handle": "row" } ], "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" }, { "jsonSchema": { "type": "array", "items": { "type": "array", "items": { "anyOf": [ { "type": "string", "description": "A union variant." }, { "type": "number", "description": "A union variant." }, { "type": "boolean", "description": "A union variant." }, { "const": null, "description": "A union variant." } ], "description": "The cell value schema." }, "description": "An array item." }, "description": "The data to append." }, "nullable": false, "handle": "values" }, { "jsonSchema": { "type": "boolean" }, "nullable": false, "handle": "nonempty" } ], "name": "Choose the next message", "moduleId": "n_8bf704265f3ff3ef", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } }, "n_5e060dc91a34ccc5": { "inputs": {}, "name": "Any messages remaining", "kind": "condition", "matchMode": "first", "cases": [ { "output": "more", "groups": [ { "expressions": [ { "left": { "kind": "source", "source": { "kind": "node", "nodeId": "n_1cd1af7756035155", "output": "more" } }, "operator": "==", "right": { "kind": "value", "value": true } } ] } ] } ] }, "n_13fb7a9c23da066d": { "inputs": { "messageId": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_1cd1af7756035155", "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_160a99282514a829": { "inputs": { "expectedId": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_1cd1af7756035155", "output": "messageId" } ] }, "messageId": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_13fb7a9c23da066d", "output": "messageId" } ] }, "sender": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_13fb7a9c23da066d", "output": "sender" } ] }, "subject": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_13fb7a9c23da066d", "output": "subject" } ] }, "snippet": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_13fb7a9c23da066d", "output": "snippet" } ] } }, "name": "Prepare the sheet row", "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 sender value." }, "nullable": false, "handle": "sender" }, { "jsonSchema": { "type": "string", "description": "Normalized message subject line." }, "nullable": false, "handle": "subject" }, { "jsonSchema": { "type": "string", "description": "The message snippet." }, "nullable": true, "handle": "snippet" } ], "outputs": [ { "jsonSchema": { "type": "object", "additionalProperties": true }, "nullable": false, "handle": "row" } ], "name": "Prepare the sheet row", "moduleId": "n_33aef51868642e6c", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } }, "n_243e69165310d4fa": { "inputs": {}, "name": "Any messages to append", "kind": "condition", "matchMode": "first", "cases": [ { "output": "nonempty", "groups": [ { "expressions": [ { "left": { "kind": "source", "source": { "kind": "node", "nodeId": "n_1cd1af7756035155", "output": "nonempty" } }, "operator": "==", "right": { "kind": "value", "value": true } } ] } ] } ] }, "n_6f022fe022db85fe": { "inputs": { "spreadsheetId": { "kind": "value", "value": "YOUR_SPREADSHEET_ID" }, "range": { "kind": "value", "value": "Sheet1!A:C" }, "values": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_1cd1af7756035155", "output": "values" } ] }, "majorDimension": { "kind": "value", "value": "ROWS" }, "insertDataOption": { "kind": "value", "value": "INSERT_ROWS" }, "valueInputOption": { "kind": "value", "value": "USER_ENTERED" } }, "name": "Append the message row", "kind": "task", "task": { "inputs": [ { "description": "The spreadsheet ID.", "jsonSchema": { "type": "string", "minLength": 1, "description": "The spreadsheet ID." }, "nullable": true, "handle": "spreadsheetId", "value": null }, { "description": "The A1 notation of the range to append values after.", "jsonSchema": { "type": "string", "minLength": 1, "description": "The A1 notation of the range to append values after." }, "nullable": false, "handle": "range" }, { "description": "The data to append.", "jsonSchema": { "type": "array", "items": { "type": "array", "items": { "anyOf": [ { "type": "string", "description": "A union variant." }, { "type": "number", "description": "A union variant." }, { "type": "boolean", "description": "A union variant." }, { "const": null, "description": "A union variant." } ], "description": "The cell value schema." }, "description": "An array item." }, "description": "The data to append." }, "nullable": false, "handle": "values" }, { "description": "The major dimension of the values array.", "jsonSchema": { "type": "string", "enum": [ "ROWS", "COLUMNS" ], "description": "The major dimension of the values array." }, "nullable": true, "handle": "majorDimension", "value": null }, { "description": "How the data should be inserted.", "jsonSchema": { "type": "string", "enum": [ "OVERWRITE", "INSERT_ROWS" ], "description": "How the data should be inserted." }, "nullable": true, "handle": "insertDataOption", "value": null }, { "description": "How the input data should be interpreted.", "jsonSchema": { "type": "string", "enum": [ "RAW", "USER_ENTERED" ], "description": "How the input data should be interpreted." }, "nullable": true, "handle": "valueInputOption", "value": null }, { "description": "Whether to include the appended values in the response.", "jsonSchema": { "type": "boolean", "description": "Whether to include the appended values in the response." }, "nullable": true, "handle": "includeValuesInResponse", "value": null }, { "description": "How values in the response should be rendered.", "jsonSchema": { "type": "string", "enum": [ "FORMATTED_VALUE", "UNFORMATTED_VALUE", "FORMULA" ], "description": "How values in the response should be rendered." }, "nullable": true, "handle": "responseValueRenderOption", "value": null }, { "description": "How dates in the response should be rendered.", "jsonSchema": { "type": "string", "enum": [ "SERIAL_NUMBER", "FORMATTED_STRING" ], "description": "How dates in the response should be rendered." }, "nullable": true, "handle": "responseDateTimeRenderOption", "value": null } ], "outputs": [ { "description": "The unique ID of the spreadsheet.", "jsonSchema": { "type": "string", "description": "The unique ID of the spreadsheet." }, "nullable": false, "handle": "spreadsheetId" }, { "description": "The A1 notation of the range that was updated.", "jsonSchema": { "type": "string", "description": "The A1 notation of the range that was updated." }, "nullable": false, "handle": "updatedRange" }, { "description": "The number of rows that were updated.", "jsonSchema": { "type": "integer", "description": "The number of rows that were updated." }, "nullable": false, "handle": "updatedRows" }, { "description": "The number of columns that were updated.", "jsonSchema": { "type": "integer", "description": "The number of columns that were updated." }, "nullable": false, "handle": "updatedColumns" }, { "description": "The number of cells that were updated.", "jsonSchema": { "type": "integer", "description": "The number of cells that were updated." }, "nullable": false, "handle": "updatedCells" }, { "description": "The values of the cells after the update.", "jsonSchema": { "type": "object", "properties": { "range": { "type": "string", "description": "The A1 notation of the range." }, "majorDimension": { "type": "string", "description": "The major dimension of the values (ROWS or COLUMNS)." }, "values": { "type": "array", "items": { "type": "array", "items": { "anyOf": [ { "type": "string", "description": "A union variant." }, { "type": "number", "description": "A union variant." }, { "type": "boolean", "description": "A union variant." }, { "const": null, "description": "A union variant." } ], "description": "The cell value schema." }, "description": "An array item." }, "description": "The data values in the range." } }, "required": [ "range", "majorDimension", "values" ], "additionalProperties": false, "description": "The values of the cells after the update." }, "nullable": true, "handle": "updatedData" }, { "description": "The A1 notation of the table range that data was appended to.", "jsonSchema": { "type": "string", "description": "The A1 notation of the table range that data was appended to." }, "nullable": false, "handle": "tableRange" } ], "name": "Append the message row", "executor": { "kind": "connector", "action": "googlesheets.spreadsheets_values_append" } } }, "n_d2dfe5ab69e50e6d": { "inputs": { "count": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_1cd1af7756035155", "output": "count" } ] }, "updatedRows": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_6f022fe022db85fe", "output": "updatedRows" } ] } }, "name": "Confirm the appended page", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "integer", "minimum": 0 }, "nullable": false, "handle": "count" }, { "jsonSchema": { "type": "integer", "description": "The number of rows that were updated." }, "nullable": false, "handle": "updatedRows" } ], "outputs": [ { "jsonSchema": { "type": "integer", "minimum": 0 }, "nullable": false, "handle": "count" } ], "name": "Confirm the appended page", "moduleId": "n_a19b9a793ce37b7b", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } }, "n_7a081ba15b711c2f": { "name": "Number of appended messages", "kind": "outputs", "outputDefs": [ { "jsonSchema": { "type": "integer", "minimum": 0 }, "nullable": false, "handle": "count" } ], "outputMappings": { "count": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_1cd1af7756035155", "output": "count" } ] } } } }, "edges": [ { "source": "n_b5c9b81a3be65b67", "target": "n_1cd1af7756035155" }, { "source": "n_1cd1af7756035155", "target": "n_5e060dc91a34ccc5" }, { "source": "n_5e060dc91a34ccc5", "target": "n_13fb7a9c23da066d", "sourceHandle": "more" }, { "source": "n_13fb7a9c23da066d", "target": "n_160a99282514a829" }, { "source": "n_160a99282514a829", "target": "n_1cd1af7756035155" }, { "source": "n_5e060dc91a34ccc5", "target": "n_243e69165310d4fa", "sourceHandle": "otherwise" }, { "source": "n_243e69165310d4fa", "target": "n_6f022fe022db85fe", "sourceHandle": "nonempty" }, { "source": "n_243e69165310d4fa", "target": "n_7a081ba15b711c2f", "sourceHandle": "otherwise" }, { "source": "n_6f022fe022db85fe", "target": "n_d2dfe5ab69e50e6d" }, { "source": "n_d2dfe5ab69e50e6d", "target": "n_7a081ba15b711c2f" } ] } }, "modules": { "n_8bf704265f3ff3ef": { "name": "Choose the next message", "imports": [], "source": "export default function gmailSheetProgress({ events, previousState, row }) {\n if (!Array.isArray(events) || events.length > 50) throw new Error('Invalid Gmail poll page');\n for (const event of events) if (!event || typeof event.messageId !== 'string' || !event.messageId) throw new Error('Missing Gmail message ID');\n let state = { index: 0, values: [] };\n if (previousState != null) {\n if (!Number.isInteger(previousState.index) || previousState.index < 0 || previousState.index >= events.length || !Array.isArray(previousState.values) || previousState.values.length !== previousState.index || !row || !Array.isArray(row.values) || row.values.length !== 3) throw new Error('Invalid Gmail page progress');\n state = { index: previousState.index + 1, values: previousState.values.concat([row.values]) };\n }\n return { state, more: state.index < events.length, messageId: state.index < events.length ? events[state.index].messageId : '', count: state.index, values: state.values, nonempty: state.index > 0 };\n}\n" }, "n_33aef51868642e6c": { "name": "Prepare the sheet row", "imports": [], "source": "export default function gmailSheetRow({ expectedId, messageId, sender, subject, snippet }) {\n if (messageId !== expectedId) throw new Error('Fetched a different Gmail message');\n if (typeof sender !== 'string' || typeof subject !== 'string' || (snippet != null && typeof snippet !== 'string')) throw new Error('Invalid Gmail message fields');\n return { row: { values: [sender, subject, snippet ?? ''] } };\n}\n" }, "n_a19b9a793ce37b7b": { "name": "Confirm the appended page", "imports": [], "source": "export default function gmailSheetConfirm({ count, updatedRows }) {\n if (count < 1 || updatedRows !== count) throw new Error('The sheet did not confirm the full batch; inspect it before replaying');\n return { count };\n}\n" } } }, "presentation": { "designer": { "version": 1, "flow": { "direction": "vertical" } } } }