This workflow follows the Gmail → Gmail Trigger recipe pattern — see all workflows that pair these two integrations.
The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →
{
"meta": {
"versionId": "1.0.0",
"createdAt": "2025-09-29T07:07:42.506870",
"updatedAt": "2025-09-29T07:07:42.506896",
"owner": "n8n-user",
"license": "MIT",
"category": "automation",
"status": "active",
"priority": "high",
"environment": "production"
},
"nodes": [
{
"id": "7d11aa76-c7bf-4aa3-9f94-fb2231f5055b",
"name": "Loop Over Items",
"type": "n8n-nodes-base.splitInBatches",
"position": [
-1460,
2080
],
"parameters": {
"options": {}
},
"typeVersion": 3,
"notes": "This splitInBatches node performs automated tasks as part of the workflow."
},
{
"id": "bea6febe-077f-4b90-887c-9c82954ef5d9",
"name": "Fetch Linear team details",
"type": "n8n-nodes-base.graphql",
"position": [
-1220,
1760
],
"parameters": {
"query": "=query GetTeamsAndProjects {\n teams(filter: {name: {contains: \"{{ $json['Linear team name'] }}\"}}) {\n nodes {\n id\n name\n members {\n nodes {\n id\n name\n email\n }\n }\n projects {\n nodes {\n id\n name\n description\n }\n }\n }\n }\n}\n",
"endpoint": "{{ $env.API_BASE_URL }}",
"requestMethod": "GET",
"authentication": "{{ $credentials.headerAuth }}"
},
"credentials": {
"httpHeaderAuth": {
"name": "<your credential>"
}
},
"executeOnce": true,
"typeVersion": 1,
"continueOnFail": true,
"notes": "This graphql node performs automated tasks as part of the workflow."
},
{
"id": "27a2111b-716b-4150-af92-ab90d7e83642",
"name": "Get issue contents",
"type": "n8n-nodes-base.notion",
"position": [
-1220,
2340
],
"parameters": {
"blockId": {
"__rl": true,
"mode": "id",
"value": "={{ $('Set assignee and title').item.json.id }}"
},
"resource": "block",
"operation": "getAll",
"returnAll": true,
"simplifyOutput": false,
"fetchNestedBlocks": true
},
"credentials": {
"notionApi": {
"name": "<your credential>"
}
},
"typeVersion": 2.1,
"alwaysOutputData": true,
"notes": "This notion node performs automated tasks as part of the workflow."
},
{
"id": "96bde9b1-b84e-445a-b90c-6dd4031076aa",
"name": "Aggregate",
"type": "n8n-nodes-base.aggregate",
"position": [
-560,
2340
],
"parameters": {
"options": {},
"fieldsToAggregate": {
"fieldToAggregate": [
{
"fieldToAggregate": "markdown"
}
]
}
},
"typeVersion": 1,
"notes": "This aggregate node performs automated tasks as part of the workflow."
},
{
"id": "45c63a2d-d457-4882-ac99-4b8e4a63ae43",
"name": "Prepare issue data",
"type": "n8n-nodes-base.set",
"position": [
-1220,
2620
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "e1b44489-ee32-4da4-816e-f56d640a9731",
"name": "title",
"type": "string",
"value": "={{ $if($('Set assignee and title').item.json.title.length <= 70, $('Set assignee and title').item.json.title, $('Shorten title').item.json.message.content) }}"
},
{
"id": "f3fab4f6-8ea3-4b93-91ea-ec08c2d9eded",
"name": "description",
"type": "string",
"value": "=_Issue created automatically from a [Notion block]({{ $('Set page URL').last().json.page_url + '?pvs=4#' + $('Loop Over Items').item.json.id.replaceAll('-', '') }})_ {{ $if($('Set assignee and title').item.json.assignee_fragment && !$('Set assignee and title').item.json.assignee, \"\\nAssignee '\" + $('Set assignee and title').item.json.assignee_fragment + \"' not found\", '') }}\n\n{{ $json.markdown?.join('\\n') }}"
}
]
}
},
"typeVersion": 3.3,
"notes": "This set node performs automated tasks as part of the workflow."
},
{
"id": "ce619c7d-8363-48ec-86c8-a1f16097eb3e",
"name": "Create linear issue",
"type": "n8n-nodes-base.linear",
"position": [
-1000,
2620
],
"parameters": {
"title": "={{ $json.title }}",
"teamId": "={{ $('Set team ID').item.json.team_id }}",
"additionalFields": {
"assigneeId": "={{ $('Set assignee and title').item.json.assignee.id }}",
"description": "={{ $json.description }}"
}
},
"credentials": {
"linearApi": {
"name": "<your credential>"
}
},
"typeVersion": 1,
"notes": "This linear node performs automated tasks as part of the workflow."
},
{
"id": "cc365fa1-a2cc-430c-8cb4-5d708b7a66b9",
"name": "Set assignee and title",
"type": "n8n-nodes-base.code",
"position": [
-1220,
2080
],
"parameters": {
"mode": "runOnceForEachItem",
"jsCode": "// Set the title and the assignee based on the first line of the item\n\nlet firstLine = $json[$json.type].text.reduce((s, o) => {\n return s + o.text.content\n}, \"\")\nconsole.log('firstLin', firstLine)\nconst regex = /^(\\[[^\\]]*\\]\\s)?(.+)$/;\nconst match = firstLine.match(regex);\nconsole.log('match', match)\n\nif (match) {\n // If the first part is not present, match[1] will be undefined\n item.json.assignee_fragment = match[1]?.slice(1, -2) || null;\n item.json.title = match[2];\n} else {\n item.json.title = firstLine;\n item.json.assignee_fragment = null;\n}\n\n// Set the new title in Notion format\n// $url will be set later, once we have it\nconst prefix_link = [\n {\"text\":{\"content\":\"[\"}},\n {\"text\":{\"content\":\"In Linear\", \"link\":{\"url\": \"$url\"} }},\n {\"text\":{\"content\":\"] \"}}\n]\nitem.json.new_content = {\n \"rich_text\": [...prefix_link, ...item.json.to_do.text]\n}\n\n// Find a matching assignee\nconst members = $('Fetch Linear team details').item.json.data.teams.nodes[0].members.nodes\nconsole.log('people', members)\nconsole.log('fragment', item.json.assignee_fragment)\nconst matching_people = members.filter(p => \n p.name.toLowerCase().startsWith(item.json.assignee_fragment?.toLowerCase())\n)\nconsole.log('mpeople', matching_people)\nif (matching_people.length > 0) {\n item.json.assignee = matching_people[0]\n}\n\nitem.pairedItem = 0\n\nreturn item"
},
"typeVersion": 2,
"notes": "This code node performs automated tasks as part of the workflow."
},
{
"id": "15d9c526-95f3-4209-9a9f-a0ba4c09a67e",
"name": "Team missing?",
"type": "n8n-nodes-base.if",
"position": [
-1000,
1760
],
"parameters": {
"options": {},
"conditions": {
"options": {
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "047fbe62-ebab-44ab-89b1-232f5f15874d",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
},
"leftValue": "={{ $json.data.teams?.nodes?.length < 1 }}",
"rightValue": ""
}
]
}
},
"typeVersion": 2,
"notes": "This if node performs automated tasks as part of the workflow."
},
{
"id": "491a1176-18a7-442a-8f64-a8c946ac25dc",
"name": "Set page URL",
"type": "n8n-nodes-base.set",
"position": [
-1000,
2340
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "0b0ced59-14c9-43e9-a5ee-f4b1862fccd6",
"name": "page_url",
"type": "string",
"value": "={{ $('n8n Form Trigger').item.json['Notion block URL'].substr(0, $('n8n Form Trigger').item.json['Notion block URL'].indexOf('?')) || $('n8n Form Trigger').item.json['Notion block URL'] }}"
},
{
"id": "3df2b2e6-38ca-4fb6-b00c-e3a6ceb3f9b3",
"name": "root_content",
"type": "object",
"value": "={{ $('Set assignee and title').item.json[$('Set assignee and title').item.json.type] }}"
},
{
"id": "41a18b43-49fd-45a5-850d-55b9f08f9b93",
"name": "root_id",
"type": "string",
"value": "={{ $('Set assignee and title').item.json.id }}"
}
]
},
"includeOtherFields": true
},
"typeVersion": 3.3,
"notes": "This set node performs automated tasks as part of the workflow."
},
{
"id": "bd107990-b009-4b81-8fee-a80c9ab09b4c",
"name": "Set team ID",
"type": "n8n-nodes-base.set",
"position": [
-740,
1760
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "b22a4a67-67b5-415a-ab38-4d7f781e8b7e",
"name": "team_id",
"type": "string",
"value": "={{ $json.data.teams.nodes[0].id }}"
}
]
}
},
"typeVersion": 3.3,
"notes": "This set node performs automated tasks as part of the workflow."
},
{
"id": "010105b6-38a2-4859-9e5d-b9624addeacc",
"name": "Add link to Notion block",
"type": "n8n-nodes-base.httpRequest",
"position": [
-560,
2620
],
"parameters": {
"url": "{{ $env.BASE_URL }}",
"method": "PATCH",
"options": {},
"jsonBody": "={\n \"to_do\":\n {{ JSON.stringify($('Set assignee and title').item.json.new_content).replace('$url', $json.data.issue.url) }}\n}",
"sendBody": true,
"sendHeaders": true,
"specifyBody": "json",
"authentication": "{{ $credentials.predefinedCredentialType }}",
"headerParameters": {
"parameters": [
{
"name": "Notion-Version",
"value": "2022-06-28"
}
]
},
"nodeCredentialType": "YOUR_CREDENTIAL_HERE"
},
"credentials": {
"notionApi": {
"name": "<your credential>"
}
},
"typeVersion": 4.1,
"notes": "This httpRequest node performs automated tasks as part of the workflow."
},
{
"id": "bb88f7df-deef-4c9d-b8af-3e59bf0e0b7d",
"name": "Get issue URL",
"type": "n8n-nodes-base.graphql",
"position": [
-780,
2620
],
"parameters": {
"query": "=query IssueDetails {\n issue(id: \"{{ $json.id }}\") {\n url\n }\n}",
"endpoint": "{{ $env.API_BASE_URL }}",
"requestMethod": "GET",
"authentication": "{{ $credentials.headerAuth }}"
},
"credentials": {
"httpHeaderAuth": {
"name": "<your credential>"
}
},
"executeOnce": true,
"typeVersion": 1,
"continueOnFail": true,
"notes": "This graphql node performs automated tasks as part of the workflow."
},
{
"id": "00736596-08ee-4ff6-b907-bd454dd406d9",
"name": "Shorten title",
"type": "n8n-nodes-base.noOp",
"position": [
-1000,
2080
],
"parameters": {
"modelId": {
"__rl": true,
"mode": "list",
"value": "gpt-4",
"cachedResultName": "GPT-4"
},
"options": {},
"messages": {
"values": [
{
"content": "=Make the following text more concise, so that it's max 150 chars long. If it's already less than 70 chars long, just return the original text. Do not return anything else other than the text.\n\nTEXT:\n{{ $json.title }}"
}
]
}
},
"credentials": {
"openAiApi": {
"name": "<your credential>"
}
},
"typeVersion": 1,
"notes": "This openAi node performs automated tasks as part of the workflow."
},
{
"id": "729928a2-8a5e-4b25-82be-ba1916b9953f",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1260,
2020
],
"parameters": {
"color": 7,
"width": 877.8549621677266,
"height": 214.7985362687051,
"content": "### Figure out issue assignee and title (shortening if necessary)"
},
"typeVersion": 1,
"notes": "This stickyNote node performs automated tasks as part of the workflow."
},
{
"id": "86d3b72f-f235-4b37-877f-c8ab1f39ba30",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1260,
2280
],
"parameters": {
"color": 7,
"width": 877.8549621677266,
"height": 216.9904777194533,
"content": "### Compose issue description"
},
"typeVersion": 1,
"notes": "This stickyNote node performs automated tasks as part of the workflow."
},
{
"id": "01c06352-76fa-4d63-b37b-2a0239d81302",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1260,
2560
],
"parameters": {
"color": 7,
"width": 877.8549621677266,
"height": 216.9904777194533,
"content": "### Create issue and add link to it in Notion"
},
"typeVersion": 1,
"notes": "This stickyNote node performs automated tasks as part of the workflow."
},
{
"id": "1f152f08-0c5a-4806-bd85-7e9a5e386fe4",
"name": "Sticky Note5",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1260,
1500
],
"parameters": {
"color": 7,
"width": 1164.99929221574,
"height": 442.760447146518,
"content": "### Get the issues to create from Notion (and load Linear team details)"
},
"typeVersion": 1,
"notes": "This stickyNote node performs automated tasks as part of the workflow."
},
{
"id": "839d1815-419d-4acb-8668-94f1cbe45f1f",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1780,
1700
],
"parameters": {
"height": 278.9250421966361,
"content": "# Try me out\n1. In the form trigger node, enter the names of your Linear team(s) to display on the form \n2. Make sure your Notion page is formatted according to the [spec]({{ $env.WEBHOOK_URL }} and shared with your Notion integration\n2. Click the 'test workflow' button below"
},
"typeVersion": 1,
"notes": "This stickyNote node performs automated tasks as part of the workflow."
},
{
"id": "f9bc6e67-a9f0-4c9b-a9b3-fdea1fd9de3e",
"name": "Unimported, unchecked to_do blocks only",
"type": "n8n-nodes-base.filter",
"position": [
-220,
1760
],
"parameters": {
"options": {},
"conditions": {
"options": {
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "d7e85c09-8548-4fc8-a8a9-636e4529e9d9",
"operator": {
"name": "filter.operator.equals",
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.type }}",
"rightValue": "to_do"
},
{
"id": "13fb565d-8951-4c89-9684-85c357459794",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
},
"leftValue": "={{ !$json.to_do.text.reduce((s, o) => s + o.plain_text, \"\").startsWith('[In Linear]') }}",
"rightValue": ""
},
{
"id": "0a9c8e94-11ec-4317-8de5-f22862555b78",
"operator": {
"type": "boolean",
"operation": "false",
"singleValue": true
},
"leftValue": "={{ $json.to_do.checked }}",
"rightValue": ""
}
]
}
},
"typeVersion": 2,
"notes": "This filter node performs automated tasks as part of the workflow."
},
{
"id": "186a4272-4550-441e-9ef2-66de2dac5b8a",
"name": "n8n Form Trigger",
"type": "n8n-nodes-base.formTrigger",
"position": [
-1460,
1760
],
"parameters": {
"path": "5a631d63-f899-4967-acad-69924674e96a",
"formTitle": "Import Linear issues from Notion",
"formFields": {
"values": [
{
"fieldLabel": "Notion page URL",
"requiredField": true
},
{
"fieldType": "dropdown",
"fieldLabel": "Linear team name",
"fieldOptions": {
"values": [
{
"option": "AI"
},
{
"option": "Adore"
},
{
"option": "Payday"
},
{
"option": "NODES"
}
]
},
"requiredField": true
}
]
},
"responseMode": "responseNode",
"formDescription": "More information on Notion formatting required here: {{ $env.WEBHOOK_URL }}"
},
"typeVersion": 2,
"notes": "This formTrigger node performs automated tasks as part of the workflow."
},
{
"id": "0fed5dbe-54e9-4bc3-8ab3-6175347ecce7",
"name": "Get issues",
"type": "n8n-nodes-base.notion",
"onError": "continueErrorOutput",
"position": [
-500,
1760
],
"parameters": {
"blockId": {
"__rl": true,
"mode": "url",
"value": "={{ $('n8n Form Trigger').item.json['Notion page URL'] }}"
},
"resource": "block",
"operation": "getAll",
"returnAll": true,
"simplifyOutput": false
},
"credentials": {
"notionApi": {
"name": "<your credential>"
}
},
"typeVersion": 2.1,
"notes": "This notion node performs automated tasks as part of the workflow."
},
{
"id": "7cc756ad-55f3-4596-989a-df90d4c829c7",
"name": "Convert contents to Markdown",
"type": "n8n-nodes-base.code",
"position": [
-780,
2340
],
"parameters": {
"jsCode": "function extractMarkdown(obj) {\n console.log('obj', obj.text)\n return obj.text.reduce((s, o) => {\n if(o.text?.link) {\n return s + '[' + o.text.content + '](' + o.text.link?.url + ')'\n }\n return s + o.text.content\n }, \"\")\n}\n\n\nconst indent = \" \"; // Four spaces\nlet parent_ids = [$input.all()[0].json.root_id]\n\nfor(item of $input.all()){\n\n // Generate the markdown\n\n if(item.json.type) {\n \n const type = item.json.type\n \n if(type == 'bulleted_list_item' || type == 'toggle') {\n item.json.markdown = '* ' + extractMarkdown(item.json[type])\n } else if(type == 'numbered_list_item') {\n item.json.markdown = '1. ' + extractMarkdown(item.json[type])\n } else if(type == 'to_do') {\n item.json.markdown = '+ [ ] ' + extractMarkdown(item.json[type])\n } else if(type == 'image') {\n item.json.markdown = ''\n } else if(type == 'video') {\n item.json.markdown = '[\ud83c\udfac Video]('+$input.all()[0].json.page_url + '?pvs=4#' + item.json.id.replaceAll('-', '') +')'\n } else {\n item.json.markdown = extractMarkdown(item.json[type])\n }\n \n // Figure out how much to indent it\n // If parent ID is in list, remove everything after that ID\n // If parent ID is not in list, add it\n // If parent is the same, do nothing\n const parent_id_index = parent_ids.indexOf(item.json.parent_id);\n \n // Check if the value is found\n if (parent_id_index !== -1) {\n // Remove all elements after the first occurrence\n parent_ids.splice(parent_id_index + 1);\n } else {\n parent_ids.push(item.json.parent_id)\n }\n \n // Indent the markdown\n //if (type != \"image\") {\n item.json.markdown = indent.repeat(parent_ids.length - 1) + item.json.markdown\n //}\n }\n}\n\n// On returning, add in the root block content at the beginning\nreturn [\n ...[\n {\n \"json\": {\n \"markdown\":\nextractMarkdown($input.all()[0].json.root_content)\n },\n \"pairedItem\": 0\n }\n ],\n ...$input.all()\n]"
},
"typeVersion": 2,
"notes": "This code node performs automated tasks as part of the workflow."
},
{
"id": "2bbd43a2-aebe-4ee5-8682-d76791214168",
"name": "Respond with error",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
-220,
1580
],
"parameters": {
"options": {},
"respondWith": "json",
"responseBody": "{\n \"formSubmittedText\": \"Couldn't fetch page content from Notion. Is it shared with your Notion integration?\"\n}"
},
"typeVersion": 1,
"notes": "This respondToWebhook node performs automated tasks as part of the workflow."
},
{
"id": "c39912c4-d33f-4d79-9d5c-e71bd0f2517d",
"name": "Respond with error1",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
-740,
1580
],
"parameters": {
"options": {},
"respondWith": "json",
"responseBody": "={\n \"formSubmittedText\": \"Couldn't find the team called '\" + {{ $('n8n Form Trigger').item.json['Linear team name'] }} + \"'\"\n} "
},
"typeVersion": 1,
"notes": "This respondToWebhook node performs automated tasks as part of the workflow."
}
],
"connections": {
"Add link to Notion block": {
"main": [
[],
[],
[],
[],
[],
[],
[],
[],
[]
]
},
"Respond with error": {
"main": [
[],
[],
[],
[],
[],
[],
[],
[],
[]
]
},
"Respond with error1": {
"main": [
[],
[],
[],
[],
[],
[],
[],
[],
[]
]
},
"Shorten title": {
"main": [
[]
]
}
},
"name": "Splitinbatches Workflow",
"settings": {
"executionOrder": "v1",
"saveManualExecutions": true,
"callerPolicy": "workflowsFromSameOwner",
"errorWorkflow": null,
"timezone": "UTC",
"executionTimeout": 3600,
"maxExecutions": 1000,
"retryOnFail": true,
"retryCount": 3,
"retryDelay": 1000
},
"description": "Automated workflow: Splitinbatches Workflow. This workflow integrates 15 different services: stickyNote, httpRequest, filter, formTrigger, code. It contains 31 nodes and follows best practices for error handling and security.",
"notes": "Excellent quality workflow: Splitinbatches Workflow. This workflow has been optimized for production use with comprehensive error handling, security, and documentation.",
"id": "wfec9331910832"
}
Credentials you'll need
Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.
gmailOAuth2slackOAuth2Api
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Splitinbatches Workflow. Uses gmail, gmailTrigger, slack, stopAndError. Event-driven trigger; 7 nodes.
Source: https://github.com/fsebbah/n8n-workflows/blob/4ef2981e7f9682bf0695bbd353d5ee75d3215475/workflows/Splitinbatches_Workflow.json — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
Splitinbatches Workflow. Uses gmail, gmailTrigger, slack, stopAndError. Event-driven trigger; 7 nodes.
Categories: Payments, Project Operations, Client Onboarding
Stickynote Workflow. Uses stickyNote, gmailTrigger, gmail, noOp. Event-driven trigger; 20 nodes.
Gmailtrigger Workflow. Uses gmailTrigger, gmail, splitOut, noOp. Event-driven trigger; 20 nodes.
Automatically transform resume submissions into comprehensive candidate profiles with AI-powered parsing, GitHub analysis, and instant team notifications. Monitors Gmail for incoming resume attachment