{ "kind": "open-flow-workflow", "version": 1, "name": "Save Gmail Attachments to Google Drive", "content": { "modelVersion": 14, "document": { "bindings": {}, "graph": { "nodes": { "n_9c0e0d219024ecf1": { "name": "Check for new attachments every minute", "kind": "poll", "config": { "labelNamesOrIds": { "kind": "value", "value": [] }, "readStatus": { "kind": "value", "value": "All" }, "search": { "kind": "value", "value": "has:attachment" }, "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_f24f2416a30d5ee2": { "inputs": { "events": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_9c0e0d219024ecf1", "output": "events" } ] }, "previousState": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_f24f2416a30d5ee2", "output": "state" } ] } }, "name": "Choose the next email", "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" } ], "name": "Choose the next email", "moduleId": "n_52994d5e3fba25f6", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } }, "n_7501e2bb58504847": { "inputs": {}, "name": "More emails?", "kind": "condition", "matchMode": "first", "cases": [ { "output": "more", "groups": [ { "expressions": [ { "left": { "kind": "source", "source": { "kind": "node", "nodeId": "n_f24f2416a30d5ee2", "output": "more" } }, "operator": "==", "right": { "kind": "value", "value": true } } ] } ] } ] }, "n_7008790220d2bc3f": { "inputs": { "messageId": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_f24f2416a30d5ee2", "output": "messageId" } ] }, "format": { "kind": "value", "value": "full" } }, "name": "Read email and attachments", "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": "Read email and attachments", "executor": { "kind": "connector", "action": "gmail.fetch_message_by_message_id" } } }, "n_8231c69d88b5f47c": { "inputs": { "expectedId": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_f24f2416a30d5ee2", "output": "messageId" } ] }, "messageId": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_7008790220d2bc3f", "output": "messageId" } ] }, "sender": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_7008790220d2bc3f", "output": "sender" } ] }, "attachmentList": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_7008790220d2bc3f", "output": "attachmentList" } ] }, "payload": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_7008790220d2bc3f", "output": "payload" } ] }, "previousState": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_8231c69d88b5f47c", "output": "state" } ] }, "folderId": { "kind": "value", "value": "YOUR_DRIVE_FOLDER_ID" } }, "name": "Choose the next attachment", "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": "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" }, { "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" }, { "jsonSchema": { "type": "object", "additionalProperties": true }, "nullable": true, "handle": "previousState" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "folderId" } ], "outputs": [ { "jsonSchema": { "type": "object", "additionalProperties": true }, "nullable": false, "handle": "state" }, { "jsonSchema": { "type": "boolean" }, "nullable": false, "handle": "more" }, { "jsonSchema": { "type": "boolean" }, "nullable": false, "handle": "remote" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "attachmentId" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "filename" }, { "jsonSchema": { "type": "string", "minLength": 1, "description": "The MIME type of the file." }, "nullable": false, "handle": "mimeType" }, { "jsonSchema": { "type": "integer", "minimum": 0, "maximum": 52428800, "description": "Attachment size in bytes returned in message metadata." }, "nullable": false, "handle": "size" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "inline" }, { "jsonSchema": { "type": "string", "minLength": 1, "description": "The name of the file." }, "nullable": false, "handle": "name" }, { "jsonSchema": { "type": "array", "items": { "type": "string", "minLength": 1, "description": "Schema for nonEmptyString." }, "minItems": 1, "description": "A list of parent folder IDs to place the file in." }, "nullable": false, "handle": "parents" } ], "name": "Choose the next attachment", "moduleId": "n_499926745bc08780", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } }, "n_dbdac8327a5a16cd": { "inputs": {}, "name": "More attachments?", "kind": "condition", "matchMode": "first", "cases": [ { "output": "more", "groups": [ { "expressions": [ { "left": { "kind": "source", "source": { "kind": "node", "nodeId": "n_8231c69d88b5f47c", "output": "more" } }, "operator": "==", "right": { "kind": "value", "value": true } } ] } ] } ] }, "n_7c61a32df58b619a": { "inputs": {}, "name": "Download attachment bytes?", "kind": "condition", "matchMode": "first", "cases": [ { "output": "remote", "groups": [ { "expressions": [ { "left": { "kind": "source", "source": { "kind": "node", "nodeId": "n_8231c69d88b5f47c", "output": "remote" } }, "operator": "==", "right": { "kind": "value", "value": true } } ] } ] } ] }, "n_1583e0534f82e460": { "inputs": { "messageId": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_f24f2416a30d5ee2", "output": "messageId" } ] }, "attachmentId": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_8231c69d88b5f47c", "output": "attachmentId" } ] }, "filename": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_8231c69d88b5f47c", "output": "filename" } ] }, "mimeType": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_8231c69d88b5f47c", "output": "mimeType" } ] }, "size": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_8231c69d88b5f47c", "output": "size" } ] } }, "name": "Download Gmail attachment", "kind": "task", "task": { "inputs": [ { "description": "Gmail message ID.", "jsonSchema": { "type": "string", "description": "Gmail message ID." }, "nullable": false, "handle": "messageId" }, { "description": "Gmail attachment ID returned in message attachment metadata.", "jsonSchema": { "type": "string", "description": "Gmail attachment ID returned in message attachment metadata." }, "nullable": false, "handle": "attachmentId" }, { "description": "Attachment filename returned in message metadata.", "jsonSchema": { "type": "string", "description": "Attachment filename returned in message metadata." }, "nullable": false, "handle": "filename" }, { "description": "Attachment MIME type returned in message metadata.", "jsonSchema": { "type": "string", "description": "Attachment MIME type returned in message metadata." }, "nullable": false, "handle": "mimeType" }, { "description": "Attachment size in bytes returned in message metadata.", "jsonSchema": { "type": "integer", "minimum": 0, "maximum": 52428800, "description": "Attachment size in bytes returned in message metadata." }, "nullable": false, "handle": "size" } ], "outputs": [ { "description": "Gmail message ID.", "jsonSchema": { "type": "string", "description": "Gmail message ID." }, "nullable": false, "handle": "messageId" }, { "description": "Gmail attachment ID returned in message attachment metadata.", "jsonSchema": { "type": "string", "description": "Gmail attachment ID returned in message attachment metadata." }, "nullable": false, "handle": "attachmentId" }, { "description": "Attachment filename returned in message metadata.", "jsonSchema": { "type": "string", "description": "Attachment filename returned in message metadata." }, "nullable": false, "handle": "filename" }, { "description": "Attachment MIME type returned in message metadata.", "jsonSchema": { "type": "string", "description": "Attachment MIME type returned in message metadata." }, "nullable": false, "handle": "mimeType" }, { "description": "Downloaded attachment size in bytes.", "jsonSchema": { "type": "integer", "description": "Downloaded attachment size in bytes." }, "nullable": false, "handle": "sizeBytes" }, { "description": "Temporary Connector file transit URL for downloading the attachment.", "jsonSchema": { "type": "string", "format": "uri", "description": "Temporary Connector file transit URL for downloading the attachment." }, "nullable": false, "handle": "transitUrl" } ], "name": "Download Gmail attachment", "executor": { "kind": "connector", "action": "gmail.download_attachment" } } }, "n_258133db4a90e18b": { "inputs": { "remote": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_8231c69d88b5f47c", "output": "remote" } ] }, "inline": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_8231c69d88b5f47c", "output": "inline" } ] }, "transitUrl": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_1583e0534f82e460", "output": "transitUrl" } ] }, "size": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_8231c69d88b5f47c", "output": "size" } ] }, "expectedMessageId": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_f24f2416a30d5ee2", "output": "messageId" } ] }, "expectedAttachmentId": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_8231c69d88b5f47c", "output": "attachmentId" } ] }, "downloadedMessageId": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_1583e0534f82e460", "output": "messageId" } ] }, "downloadedAttachmentId": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_1583e0534f82e460", "output": "attachmentId" } ] }, "downloadedSize": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_1583e0534f82e460", "output": "sizeBytes" } ] } }, "name": "Verify complete attachment", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "boolean" }, "nullable": false, "handle": "remote" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "inline" }, { "jsonSchema": { "type": "string", "format": "uri", "description": "Temporary Connector file transit URL for downloading the attachment." }, "nullable": true, "handle": "transitUrl" }, { "jsonSchema": { "type": "integer", "minimum": 0 }, "nullable": false, "handle": "size" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "expectedMessageId" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "expectedAttachmentId" }, { "jsonSchema": { "type": "string", "description": "Gmail message ID." }, "nullable": true, "handle": "downloadedMessageId" }, { "jsonSchema": { "type": "string", "description": "Gmail attachment ID returned in message attachment metadata." }, "nullable": true, "handle": "downloadedAttachmentId" }, { "jsonSchema": { "type": "integer", "description": "Downloaded attachment size in bytes." }, "nullable": true, "handle": "downloadedSize" } ], "outputs": [ { "jsonSchema": { "type": "string", "minLength": 1, "description": "Connector media upload content encoded as a Base64 string." }, "nullable": true, "handle": "contentBase64" } ], "name": "Verify complete attachment", "moduleId": "n_4b0d9c515ba76ff5", "capabilities": [ { "kind": "http", "hosts": [ "example.com" ] } ] } }, "n_b20416b9c0de14e3": { "inputs": { "name": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_8231c69d88b5f47c", "output": "name" } ] }, "mimeType": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_8231c69d88b5f47c", "output": "mimeType" } ] }, "parents": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_8231c69d88b5f47c", "output": "parents" } ] }, "contentBase64": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_258133db4a90e18b", "output": "contentBase64" } ] } }, "name": "Save attachment in Google Drive", "kind": "task", "task": { "inputs": [ { "description": "The name of the file.", "jsonSchema": { "type": "string", "minLength": 1, "description": "The name of the file." }, "nullable": true, "handle": "name", "value": null }, { "description": "The MIME type of the file.", "jsonSchema": { "type": "string", "minLength": 1, "description": "The MIME type of the file." }, "nullable": true, "handle": "mimeType", "value": null }, { "description": "A short description of the file.", "jsonSchema": { "type": "string", "minLength": 1, "description": "A short description of the file." }, "nullable": true, "handle": "description", "value": null }, { "description": "A list of parent folder IDs to place the file in.", "jsonSchema": { "type": "array", "items": { "type": "string", "minLength": 1, "description": "Schema for nonEmptyString." }, "minItems": 1, "description": "A list of parent folder IDs to place the file in." }, "nullable": true, "handle": "parents", "value": null }, { "description": "Whether the user has starred the file.", "jsonSchema": { "type": "boolean", "description": "Whether the user has starred the file." }, "nullable": true, "handle": "starred", "value": null }, { "description": "A collection of arbitrary key-value pairs which are private to the requesting app.", "jsonSchema": { "type": "object", "additionalProperties": { "type": "string", "description": "A record value." }, "description": "A collection of arbitrary key-value pairs which are private to the requesting app." }, "nullable": true, "handle": "appProperties", "value": null }, { "description": "A collection of arbitrary key-value pairs which are visible to all apps.", "jsonSchema": { "type": "object", "additionalProperties": { "type": "string", "description": "A record value." }, "description": "A collection of arbitrary key-value pairs which are visible to all apps." }, "nullable": true, "handle": "properties", "value": null }, { "description": "Connector media upload content encoded as a Base64 string.", "jsonSchema": { "type": "string", "minLength": 1, "description": "Connector media upload content encoded as a Base64 string." }, "nullable": true, "handle": "contentBase64", "value": null }, { "description": "Connector text media upload content.", "jsonSchema": { "type": "string", "description": "Connector text media upload content." }, "nullable": true, "handle": "text", "value": null } ], "outputs": [ { "description": "The unique identifier of the file.", "jsonSchema": { "type": "string", "description": "The unique identifier of the file." }, "nullable": false, "handle": "id" }, { "description": "The name of the file.", "jsonSchema": { "type": "string", "description": "The name of the file." }, "nullable": false, "handle": "name" }, { "description": "The MIME type of the file.", "jsonSchema": { "type": "string", "description": "The MIME type of the file." }, "nullable": false, "handle": "mimeType" }, { "description": "A link for opening the file in a relevant Google editor or viewer in a browser.", "jsonSchema": { "type": [ "string", "null" ], "description": "A link for opening the file in a relevant Google editor or viewer in a browser." }, "nullable": true, "handle": "webViewLink" }, { "description": "The time at which the file was created (RFC 3339 date-time).", "jsonSchema": { "type": [ "string", "null" ], "description": "The time at which the file was created (RFC 3339 date-time)." }, "nullable": true, "handle": "createdTime" }, { "description": "The last time the file was modified by anyone (RFC 3339 date-time).", "jsonSchema": { "type": [ "string", "null" ], "description": "The last time the file was modified by anyone (RFC 3339 date-time)." }, "nullable": true, "handle": "modifiedTime" }, { "description": "The size of the file's content in bytes.", "jsonSchema": { "type": [ "integer", "null" ], "description": "The size of the file's content in bytes." }, "nullable": true, "handle": "sizeBytes" }, { "description": "The ID of the shared drive the file belongs to.", "jsonSchema": { "type": [ "string", "null" ], "description": "The ID of the shared drive the file belongs to." }, "nullable": true, "handle": "driveId" }, { "description": "The IDs of the parent folders containing the file.", "jsonSchema": { "type": "array", "items": { "type": "string", "description": "An array item." }, "description": "The IDs of the parent folders containing the file." }, "nullable": true, "handle": "parents" }, { "description": "The owners of the file.", "jsonSchema": { "type": "array", "items": { "type": "object", "properties": { "displayName": { "type": [ "string", "null" ], "description": "The display name of the owner." }, "emailAddress": { "type": [ "string", "null" ], "description": "The email address of the owner." }, "permissionId": { "type": [ "string", "null" ], "description": "The permission ID of the owner." }, "photoLink": { "type": [ "string", "null" ], "description": "A link to the owner's profile photo." } }, "required": [ "displayName", "emailAddress", "permissionId", "photoLink" ], "additionalProperties": false, "description": "Schema for driveOwnerSchema." }, "description": "The owners of the file." }, "nullable": true, "handle": "owners" }, { "description": "Whether the file has been shared.", "jsonSchema": { "type": "boolean", "description": "Whether the file has been shared." }, "nullable": true, "handle": "shared" }, { "description": "Whether the user has starred the file.", "jsonSchema": { "type": "boolean", "description": "Whether the user has starred the file." }, "nullable": true, "handle": "starred" }, { "description": "Whether the file has been trashed.", "jsonSchema": { "type": "boolean", "description": "Whether the file has been trashed." }, "nullable": true, "handle": "trashed" }, { "description": "Whether the authenticated user owns the file.", "jsonSchema": { "type": "boolean", "description": "Whether the authenticated user owns the file." }, "nullable": true, "handle": "ownedByMe" }, { "description": "The projected Drive capabilities for the authenticated user.", "jsonSchema": { "type": "object", "properties": { "canShare": { "type": "boolean", "description": "Whether the authenticated user may modify sharing settings." } }, "required": [ "canShare" ], "additionalProperties": false, "description": "The projected Drive capabilities for the authenticated user." }, "nullable": true, "handle": "capabilities" } ], "name": "Save attachment in Google Drive", "executor": { "kind": "connector", "action": "googledrive.files.create" } } }, "n_63ffd9c937871fbe": { "inputs": { "id": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_b20416b9c0de14e3", "output": "id" } ] } }, "name": "Confirm the Drive file", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "string", "description": "The unique identifier of the file." }, "nullable": false, "handle": "id" } ], "outputs": [ { "jsonSchema": { "type": "boolean" }, "nullable": false, "handle": "ok" } ], "name": "Confirm the Drive file", "moduleId": "n_959fe2ee8ca5b8ea", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } } }, "edges": [ { "source": "n_9c0e0d219024ecf1", "target": "n_f24f2416a30d5ee2" }, { "source": "n_f24f2416a30d5ee2", "target": "n_7501e2bb58504847" }, { "source": "n_7501e2bb58504847", "target": "n_7008790220d2bc3f", "sourceHandle": "more" }, { "source": "n_7008790220d2bc3f", "target": "n_8231c69d88b5f47c" }, { "source": "n_8231c69d88b5f47c", "target": "n_dbdac8327a5a16cd" }, { "source": "n_dbdac8327a5a16cd", "target": "n_7c61a32df58b619a", "sourceHandle": "more" }, { "source": "n_dbdac8327a5a16cd", "target": "n_f24f2416a30d5ee2", "sourceHandle": "otherwise" }, { "source": "n_7c61a32df58b619a", "target": "n_1583e0534f82e460", "sourceHandle": "remote" }, { "source": "n_7c61a32df58b619a", "target": "n_258133db4a90e18b", "sourceHandle": "otherwise" }, { "source": "n_1583e0534f82e460", "target": "n_258133db4a90e18b" }, { "source": "n_258133db4a90e18b", "target": "n_b20416b9c0de14e3" }, { "source": "n_b20416b9c0de14e3", "target": "n_63ffd9c937871fbe" }, { "source": "n_63ffd9c937871fbe", "target": "n_8231c69d88b5f47c" } ] } }, "modules": { "n_52994d5e3fba25f6": { "name": "Choose the next email", "imports": [], "source": "export default function nextMessage({events,previousState}){if(!Array.isArray(events)||events.length>50)throw Error('Invalid Gmail poll');if(events.some(x=>!x||typeof x.messageId!=='string'||!x.messageId)||new Set(events.map(x=>x.messageId)).size!==events.length)throw Error('Invalid or repeated message ID');let index=previousState===null?0:previousState.index+1;if(!Number.isInteger(index)||index<0||index>events.length)throw Error('Invalid progress');return{state:{index},more:indexattachmentList.length)throw Error('Invalid attachment progress');\n const more=index52428800)throw Error('Invalid attachment metadata');const address=(sender.match(/<([^<>]+)>/)?.[1]??sender).trim();if(!/^[^\\s<>@,]+@[^\\s<>@,]+$/.test(address))throw Error('Missing or invalid sender address');const filename=part.filename||'attachment';const dot=filename.lastIndexOf('.');name=(dot>0?filename.slice(0,dot)+'-'+address+filename.slice(dot):filename+'-'+address);mimeType=part.mimeType||mimeType;size=part.size;attachmentId=part.attachmentId||'';if(!attachmentId){let matches=[];const walk=p=>{if(!p||typeof p!=='object')return;if(p.partId===part.partId&&typeof p.body?.data==='string')matches.push(p.body.data);for(const x of p.parts||[])walk(x)};if(part.partId===null)throw Error('Inline attachment missing part ID');walk(payload);if(matches.length!==1)throw Error('Inline attachment data is missing or ambiguous');inline=matches[0];}}\n return{state:{messageId,index},more,remote:!!attachmentId,attachmentId,filename:part?.filename||'attachment',mimeType,size,inline,name,parents:[folderId]};\n}\n" }, "n_4b0d9c515ba76ff5": { "name": "Verify complete attachment", "imports": [], "source": "import{Buffer}from'node:buffer';\nexport default async function attachmentContent({remote,inline,transitUrl,size,expectedMessageId,expectedAttachmentId,downloadedMessageId,downloadedAttachmentId,downloadedSize},context){let bytes;if(remote){if(downloadedMessageId!==expectedMessageId||downloadedAttachmentId!==expectedAttachmentId||downloadedSize!==size)throw Error('Unexpected Gmail attachment result');if(typeof transitUrl!=='string'||!/^https:\\/\\//.test(transitUrl))throw Error('Invalid attachment transit URL');const response=await context.fetch(transitUrl,{method:'GET'});if(!response.ok)throw Error('Attachment download failed');bytes=Buffer.from(await response.arrayBuffer());}else{if(typeof inline!=='string'||!/^[A-Za-z0-9_-]*={0,2}$/.test(inline))throw Error('Invalid inline attachment');const normalized=inline.replace(/-/g,'+').replace(/_/g,'/').replace(/=+$/,'');bytes=Buffer.from(normalized,'base64');if(bytes.toString('base64').replace(/=+$/,'')!==normalized)throw Error('Invalid inline attachment encoding');}if(bytes.length!==size)throw Error('Attachment size mismatch');return{contentBase64:bytes.length?bytes.toString('base64'):null};}\n" }, "n_959fe2ee8ca5b8ea": { "name": "Confirm the Drive file", "imports": [], "source": "export default function attachmentReceipt({id}){if(typeof id!=='string'||!id)throw Error('Drive did not confirm file creation; inspect Drive before retrying');return {ok:true};}\n" } } }, "presentation": { "designer": { "version": 1, "flow": { "direction": "vertical" } } } }