This workflow corresponds to n8n.io template #6501 — we link there as the canonical source.
This workflow follows the Gmail → HTTP Request 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": {
"templateCredsSetupCompleted": true
},
"nodes": [
{
"id": "af991423-1760-4a50-aee3-e090ff436eaf",
"name": "Schedule Trigger",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
-1340,
-80
],
"parameters": {
"rule": {
"interval": [
{
"field": "months",
"triggerAtHour": 8
}
]
}
},
"typeVersion": 1.2
},
{
"id": "99a30399-cc1c-4687-bc32-607a89815326",
"name": "If",
"type": "n8n-nodes-base.if",
"position": [
-740,
-80
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "loose"
},
"combinator": "and",
"conditions": [
{
"id": "61173acd-0f6c-4dd6-9cdf-bc8f166d6c63",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
},
"leftValue": "={{ $json.items.length }}",
"rightValue": ""
}
]
},
"looseTypeValidation": true
},
"typeVersion": 2.2
},
{
"id": "f3161640-ce57-4439-ab03-3b4859d5e5db",
"name": "Fetch Orders since 1 year ago",
"type": "n8n-nodes-base.httpRequest",
"position": [
-920,
-80
],
"parameters": {
"url": "=https://magekwik.com/rest/V1/orders?searchCriteria[filter_groups][0][filters][0][field]=created_at&searchCriteria[filter_groups][0][filters][0][value]={{$json[\"sixMonthsAgo\"]}} 00:00:00&searchCriteria[filter_groups][0][filters][0][condition_type]=gteq&searchCriteria[pageSize]=0",
"options": {},
"authentication": "genericCredentialType",
"genericAuthType": "httpBearerAuth"
},
"typeVersion": 4.2
},
{
"id": "6b053d22-682d-4fae-9569-4eb51d838163",
"name": "Calculate date an year ago (ISO)",
"type": "n8n-nodes-base.code",
"position": [
-1140,
-80
],
"parameters": {
"jsCode": "const date = new Date();\ndate.setMonth(date.getMonth() - 12);\nreturn [{ json: { sixMonthsAgo: date.toISOString().split('T')[0] } }];\n"
},
"typeVersion": 2
},
{
"id": "34243a56-cab5-40a8-85f7-fd3229058760",
"name": "Extract Sold SKUs from orders",
"type": "n8n-nodes-base.code",
"position": [
-440,
-80
],
"parameters": {
"jsCode": "const soldSkusSet = new Set();\n// orders response is in items\nconst orders = items[0].json.items || [];\n\norders.forEach(order => {\n if (order.items && Array.isArray(order.items)) {\n order.items.forEach(item => {\n if(item.sku) soldSkusSet.add(item.sku);\n });\n }\n});\n\nreturn [{ json: { soldSkus: Array.from(soldSkusSet) } }];"
},
"typeVersion": 2
},
{
"id": "91bfa661-893f-4940-84b4-a3f61bb098c0",
"name": "Get All Product Skus",
"type": "n8n-nodes-base.httpRequest",
"position": [
-220,
-80
],
"parameters": {
"url": "=https://magekwik.com/rest/V1/products?searchCriteria[pageSize]=0",
"options": {},
"authentication": "genericCredentialType",
"genericAuthType": "httpBearerAuth"
},
"typeVersion": 4.2
},
{
"id": "ad8c0611-3465-4b0e-bc99-6c8eb4cdb304",
"name": "Filter products NOT sold in last year",
"type": "n8n-nodes-base.code",
"position": [
0,
-80
],
"parameters": {
"jsCode": "const allProducts = $input.first().json.items || [];\nconst soldSkus = new Set($('Extract Sold SKUs from orders').first().json.soldSkus || []);\n\nconst unsoldProducts = allProducts.filter(product => {\n return !soldSkus.has(product.sku);\n});\n\nreturn [{\n json: {\n unsold: unsoldProducts\n }\n}];\n//return unsoldProducts.map(product => ({ json: product }));"
},
"typeVersion": 2
},
{
"id": "7b2f1534-4a11-4d8e-a69f-b13cbcf82660",
"name": "Gmail User for Approval",
"type": "n8n-nodes-base.gmail",
"position": [
-1300,
160
],
"parameters": {
"sendTo": "user@example.com",
"message": "=The following products have recorded zero sales over the past 12 months. To optimise inventory, we propose disabling these items in our system.\n\nNext Steps:\n\nApprove: If you agree to remove these items from active inventory.\nDecline: If you wish to retain them for sale.\n\nPlease review the list and advise on your decision within 30 minutes. Thank you for your prompt attention.\n\nBest regards,\n\n{{ $json.htmlBody }}\n",
"options": {
"appendAttribution": false
},
"subject": "=Approve disabling {{ $json.count }} unsold products ",
"operation": "sendAndWait",
"approvalOptions": {
"values": {
"approvalType": "double"
}
}
},
"typeVersion": 2.1
},
{
"id": "f0a9aac6-cc5f-4905-9016-e6e46463f2f7",
"name": "Loop Over Items",
"type": "n8n-nodes-base.splitInBatches",
"position": [
-440,
160
],
"parameters": {
"options": {
"reset": false
}
},
"typeVersion": 3,
"alwaysOutputData": false
},
{
"id": "3949b0fc-2a0b-4f71-9301-221c121b0f93",
"name": "If1",
"type": "n8n-nodes-base.if",
"position": [
-1140,
160
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "loose"
},
"combinator": "and",
"conditions": [
{
"id": "a5d805ae-81cd-42e9-a4ef-5e41f7c1960b",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
},
"leftValue": "={{ $json.data.approved }}",
"rightValue": ""
}
]
},
"looseTypeValidation": true
},
"typeVersion": 2.2
},
{
"id": "bd82188f-6ad7-4c47-a1ba-8bf7ca468c95",
"name": "Merge",
"type": "n8n-nodes-base.merge",
"position": [
-920,
160
],
"parameters": {
"mode": "chooseBranch",
"useDataOfInput": 2
},
"typeVersion": 3.2
},
{
"id": "081eb734-de23-4988-9faa-c65e4f09db13",
"name": "Split Out",
"type": "n8n-nodes-base.splitOut",
"position": [
-740,
160
],
"parameters": {
"options": {},
"fieldToSplitOut": "unsold"
},
"typeVersion": 1
},
{
"id": "c0bf16d9-6aa9-40e8-9053-98e5c5fb912e",
"name": "Disable Products",
"type": "n8n-nodes-base.httpRequest",
"position": [
-180,
400
],
"parameters": {
"url": "=https://magekwik.com/rest/default/V1/products/{{ $json.sku }}",
"method": "PUT",
"options": {},
"jsonBody": "{\n \"product\": {\n \"status\": 1\n }\n}\n",
"sendBody": true,
"specifyBody": "json",
"authentication": "genericCredentialType",
"genericAuthType": "httpBearerAuth"
},
"typeVersion": 4.2
},
{
"id": "088874ad-4ed2-4005-a5e9-3ce76ab7c8cf",
"name": "Send a message",
"type": "n8n-nodes-base.gmail",
"position": [
220,
140
],
"parameters": {
"sendTo": "user@example.com",
"message": "=The following {{ $json.count }} products have been disabled.\n\n{{ $json.htmlBody }}",
"options": {
"appendAttribution": false
},
"subject": "={{ $json.count }} products have been deactivated"
},
"typeVersion": 2.1
},
{
"id": "b4abc4dc-ca5b-41a7-bcad-ec842c348574",
"name": "Aggregate",
"type": "n8n-nodes-base.aggregate",
"position": [
-160,
160
],
"parameters": {
"include": "specifiedFields",
"options": {},
"aggregate": "aggregateAllItemData",
"fieldsToInclude": "sku,name,price,status"
},
"typeVersion": 1
},
{
"id": "9523619b-b2ca-43f0-b045-f68379eada33",
"name": "Built Reporting Email",
"type": "n8n-nodes-base.code",
"position": [
40,
140
],
"parameters": {
"jsCode": "const headers = ['sku', 'name', 'price', 'status'];\n\nconst unsold = $input.first().json.data || [];\n\n// Start the HTML table\nlet html = `<table border=\"1\" cellpadding=\"6\" cellspacing=\"0\" style=\"border-collapse: collapse; font-family: Arial, sans-serif; font-size: 14px;\">`;\n\n// Add table header\nhtml += '<tr style=\"background-color: #f2f2f2;\">' + headers.map(h => `<th>${h}</th>`).join('') + '</tr>';\n\n// Add rows\nfor (const product of unsold) {\n html += '<tr>' + headers.map(field => {\n const value = product[field] ?? '';\n return `<td>${String(value).replace(/</g, '<').replace(/>/g, '>')}</td>`;\n }).join('') + '</tr>';\n}\n\n// Close table\nhtml += '</table>';\n\nreturn [{\n json: {\n htmlBody: html,\n count: unsold.length,\n subject: `Unsold Products Report (${unsold.length})`\n }\n}];\n"
},
"typeVersion": 2
},
{
"id": "affccc45-e966-4952-9136-2f19b82ac61d",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1380,
-220
],
"parameters": {
"color": 7,
"width": 840,
"height": 300,
"content": " Fetches All Ordered SKUS last 1 Year\n"
},
"typeVersion": 1
},
{
"id": "bce6fc94-f30f-479e-8d4a-dcd946ed5e0b",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-500,
-220
],
"parameters": {
"color": 6,
"width": 840,
"height": 300,
"content": " Filters All UnOrders SKUS last 1 Year\n"
},
"typeVersion": 1
},
{
"id": "e24162fe-a07b-422c-9417-09ac72fbb534",
"name": "Build Decision Email",
"type": "n8n-nodes-base.code",
"position": [
220,
-80
],
"parameters": {
"jsCode": "const headers = ['sku', 'name', 'price', 'status'];\n\nconst unsold = $json.unsold || [];\n\n// Start the HTML table\nlet html = `<table border=\"1\" cellpadding=\"6\" cellspacing=\"0\" style=\"border-collapse: collapse; font-family: Arial, sans-serif; font-size: 14px;\">`;\n\n// Add table header\nhtml += '<tr style=\"background-color: #f2f2f2;\">' + headers.map(h => `<th>${h}</th>`).join('') + '</tr>';\n\n// Add rows\nfor (const product of unsold) {\n html += '<tr>' + headers.map(field => {\n const value = product[field] ?? '';\n return `<td>${String(value).replace(/</g, '<').replace(/>/g, '>')}</td>`;\n }).join('') + '</tr>';\n}\n\n// Close table\nhtml += '</table>';\n\nreturn [{\n json: {\n htmlBody: html,\n count: unsold.length,\n subject: `Unsold Products Report (${unsold.length})`\n }\n}];\n"
},
"typeVersion": 2
},
{
"id": "cccc4f30-ad84-472a-8c05-8f52c5692f31",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1380,
100
],
"parameters": {
"color": 5,
"width": 840,
"height": 280,
"content": " \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n If Approved, Processes the Data\n"
},
"typeVersion": 1
},
{
"id": "689407c1-c09c-44d0-a162-e42cb48aac93",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
-500,
100
],
"parameters": {
"color": 4,
"width": 840,
"height": 500,
"content": " \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n Disable Products and Reports via email\n"
},
"typeVersion": 1
},
{
"id": "b6051a73-aa8e-405e-aaaa-bbf444856a2f",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1380,
-460
],
"parameters": {
"width": 1720,
"height": 220,
"content": "# Magento 2 Inventory Cleanup: Disable Unsold Stale Products After 1 Year with Approval\n\n## This workflow is designed for merchants who want to automatically identify and deactivate products that haven't been sold in the past 12 months, helping to maintain a clean and optimized catalog. The automation includes order analysis, product comparison, management approval, and automated product deactivation, with full reporting and transparency."
},
"typeVersion": 1
}
],
"connections": {
"If": {
"main": [
[
{
"node": "Extract Sold SKUs from orders",
"type": "main",
"index": 0
}
]
]
},
"If1": {
"main": [
[
{
"node": "Merge",
"type": "main",
"index": 0
}
]
]
},
"Merge": {
"main": [
[
{
"node": "Split Out",
"type": "main",
"index": 0
}
]
]
},
"Aggregate": {
"main": [
[
{
"node": "Built Reporting Email",
"type": "main",
"index": 0
}
]
]
},
"Split Out": {
"main": [
[
{
"node": "Loop Over Items",
"type": "main",
"index": 0
}
]
]
},
"Loop Over Items": {
"main": [
[
{
"node": "Aggregate",
"type": "main",
"index": 0
}
],
[
{
"node": "Disable Products",
"type": "main",
"index": 0
}
]
]
},
"Disable Products": {
"main": [
[
{
"node": "Loop Over Items",
"type": "main",
"index": 0
}
]
]
},
"Schedule Trigger": {
"main": [
[
{
"node": "Calculate date an year ago (ISO)",
"type": "main",
"index": 0
}
]
]
},
"Build Decision Email": {
"main": [
[
{
"node": "Gmail User for Approval",
"type": "main",
"index": 0
}
]
]
},
"Get All Product Skus": {
"main": [
[
{
"node": "Filter products NOT sold in last year",
"type": "main",
"index": 0
}
]
]
},
"Built Reporting Email": {
"main": [
[
{
"node": "Send a message",
"type": "main",
"index": 0
}
]
]
},
"Gmail User for Approval": {
"main": [
[
{
"node": "If1",
"type": "main",
"index": 0
}
]
]
},
"Extract Sold SKUs from orders": {
"main": [
[
{
"node": "Get All Product Skus",
"type": "main",
"index": 0
}
]
]
},
"Fetch Orders since 1 year ago": {
"main": [
[
{
"node": "If",
"type": "main",
"index": 0
}
]
]
},
"Calculate date an year ago (ISO)": {
"main": [
[
{
"node": "Fetch Orders since 1 year ago",
"type": "main",
"index": 0
}
]
]
},
"Filter products NOT sold in last year": {
"main": [
[
{
"node": "Merge",
"type": "main",
"index": 1
},
{
"node": "Build Decision Email",
"type": "main",
"index": 0
}
]
]
}
}
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This automation includes order analysis, product comparison, management approval, and automated product deactivation, with full reporting and transparency. 1st of Every Month at 8 AM, it triggers a scheduled cleanup. Calculates the date 12 months ago from the current day.…
Source: https://n8n.io/workflows/6501/ — 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.
BSW Growth Agent · Lite (Free Tier). Uses googleSheets, googleDrive, httpRequest, gmail. Scheduled trigger; 21 nodes.
Founder's Discovery Engine. Uses googleSheets, googleDrive, httpRequest, gmail. Scheduled trigger; 21 nodes.
It identifies SKUs with low inventory per source and sends daily alerts via:
This n8n template helps Magento 2 merchants automatically send customised, beautifully branded coupon emails to high-value customers.
AI Email Agent - Self Learning. Uses gmail, httpRequest. Scheduled trigger; 14 nodes.