This workflow corresponds to n8n.io template #16541 — we link there as the canonical source.
This workflow follows the Chainllm → Anthropic Chat 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 →
{
"id": "w64d035ZutqFRqgd",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "Snowflake Inventory Reorder with Claude + Outlook",
"tags": [],
"nodes": [
{
"id": "5af5b263-1da2-46d4-a813-03a3128c1aec",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
15984,
8752
],
"parameters": {
"color": 0,
"width": 500,
"height": 932,
"content": "## Snowflake to Outlook Inventory Reorder\n\n### How it works\n\nThis workflow runs daily at 07:00 Helsinki time (Europe/Helsinki timezone), queries Snowflake for inventory items below reorder thresholds, and exits cleanly when no reorders are needed. When low-stock items exist, it groups them by supplier, loops through each vendor one at a time, generates a professional reorder email with Claude, converts it to HTML, optionally logs the activity to a Google Docs audit trail, and sends the email via Microsoft Outlook before advancing to the next supplier.\n\n### Setup\n\n1. Fill in the **Workflow Config** node at the start of the canvas:\n - `log_doc_id` \u2014 the string after /d/ in your Google Doc URL. Leave empty to skip logging.\n2. Add Snowflake credentials to **Query Snowflake DB** and verify the query returns the correct schema.\n3. Add Anthropic credentials to **Claude Email Generation**.\n4. Add Microsoft Outlook credentials to **Send Reorder Email** and **Send Error Alert**.\n5. Update `toRecipients` in the **Send Error Alert** node directly to your alert address.\n6. If logging is enabled, add Google Docs credentials to **Log to Google Docs**.\n7. In n8n Settings -> Error Workflow, point to a dedicated error-handler sub-workflow that triggers the **Send Error Alert** node.\n\n### Customization\n\nAdjust the Snowflake query, Claude prompt, email subject format, and log entry format to match your procurement process."
},
"typeVersion": 1
},
{
"id": "1ed34435-1746-4171-b551-b5da86562b1b",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
16560,
8608
],
"parameters": {
"color": 7,
"width": 1172,
"height": 776,
"content": "## Check inventory levels\n\nSchedule fires at 07:00 Helsinki time (timezone: Europe/Helsinki). Passes through Workflow Config to inject `log_doc_id`. Queries Snowflake for items where `current_stock <= reorder_level`. Exits via Pass Through when nothing needs reordering.\n"
},
"typeVersion": 1
},
{
"id": "ab4a002b-69c9-4a35-a22f-ff2f5e2ed8af",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
17824,
8592
],
"parameters": {
"color": 7,
"width": 756,
"height": 800,
"content": "## Prepare supplier batches\n\nGroups low-stock items by `supplier_name` using a Code node. Loops one supplier at a time (`batchSize: 1`). `Set Supplier Details` extracts `supplier_email` from `items[0]` (validate upstream that this field is never null), pre-renders the item list as Markdown, and pulls `log_doc_id` from Workflow Config. Routes to Complete Vendor Process when all suppliers are done."
},
"typeVersion": 1
},
{
"id": "4f07d6aa-7d1c-41e2-bf32-45a3aae85b0e",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
18640,
8592
],
"parameters": {
"color": 7,
"width": 684,
"height": 800,
"content": "## Generate email content\n\nSends the pre-rendered item list and supplier name to Claude (`claude-sonnet-4-6`, `max_tokens: 1024`) via the LLM chain. A system prompt constrains Claude to return only the email body with no preamble. The Markdown node converts the output to HTML for Outlook delivery."
},
"typeVersion": 1
},
{
"id": "abd4dd7f-b4b0-4642-b773-4d93a40b5918",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
19392,
8592
],
"parameters": {
"color": 7,
"width": 440,
"height": 800,
"content": "## Handle reorder logging\n\nChecks `log_doc_id` from Set Supplier Details. If set, appends a log entry to the Google Doc \u2014 the documentURL is built as a full URL (`https://docs.google.com/document/d/{id}/edit`) to avoid resolution errors. `continueOnFail: true` ensures a Docs error never blocks email delivery. If `log_doc_id` is empty, routes through Skip Logging."
},
"typeVersion": 1
},
{
"id": "6dc90622-8409-477b-bdf7-bf56127cd7a6",
"name": "Sticky Note5",
"type": "n8n-nodes-base.stickyNote",
"position": [
19888,
8592
],
"parameters": {
"color": 7,
"width": 380,
"height": 792,
"content": "## Send supplier email\n\nSends the HTML reorder email to the current supplier via Microsoft Outlook (`resource: message`, `operation: send`). Returns control to Loop Over Suppliers for the next vendor.\n\n`continueOnFail: true` is set so that a missing or invalid `supplier_email` does not halt the loop and skip remaining suppliers. Validate `supplier_email` is populated in your Snowflake source data."
},
"typeVersion": 1
},
{
"id": "a36fa893-d164-4b09-b86c-9895e36fec92",
"name": "Sticky Note6",
"type": "n8n-nodes-base.stickyNote",
"position": [
16560,
9440
],
"parameters": {
"color": 7,
"width": 508,
"height": 372,
"content": "##\n\n**Send Error Alert** \u2014 update `toRecipients` to your alert email address directly in the node before activating.\n\n"
},
"typeVersion": 1
},
{
"id": "c78bd3c5-c4f2-4be0-92ff-e05288b3173f",
"name": "Workflow Config",
"type": "n8n-nodes-base.set",
"position": [
16848,
9056
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "config-001",
"name": "log_doc_id",
"type": "string",
"value": ""
}
]
}
},
"typeVersion": 3.4
},
{
"id": "a03e80ff-0870-4838-90b6-ee6ccf0abb82",
"name": "When 7am Daily",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
16624,
9056
],
"parameters": {
"rule": {
"interval": [
{
"field": "cronExpression",
"expression": "0 7 * * *"
}
]
}
},
"typeVersion": 1.1
},
{
"id": "83b3069a-f5b6-44b2-9b59-e5e5857867e3",
"name": "Query Snowflake DB",
"type": "n8n-nodes-base.snowflake",
"position": [
17072,
9056
],
"parameters": {
"query": "SELECT \n item_id, \n item_name, \n current_stock, \n reorder_level, \n supplier_name, \n supplier_email \nFROM INVENTORY_DB.PUBLIC.STOCK_LEVELS \nWHERE current_stock <= reorder_level;",
"operation": "executeQuery"
},
"typeVersion": 1
},
{
"id": "5b525f3e-0470-4e3b-bb70-7d3dfea81994",
"name": "If Low Stock Exists",
"type": "n8n-nodes-base.if",
"position": [
17296,
9056
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 1,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "has-rows",
"operator": {
"type": "number",
"operation": "gt"
},
"leftValue": "={{ $input.all().length }}",
"rightValue": 0
}
]
}
},
"typeVersion": 2
},
{
"id": "78fcd8b4-887d-4151-9121-37d648d510f1",
"name": "Pass Through",
"type": "n8n-nodes-base.noOp",
"position": [
17520,
9168
],
"parameters": {},
"typeVersion": 1
},
{
"id": "1641ebad-1596-4dcd-9003-7099455e0049",
"name": "Group Items by Supplier",
"type": "n8n-nodes-base.code",
"position": [
17936,
9040
],
"parameters": {
"jsCode": "const groups = {};\n\nfor (const item of $input.all()) {\n const key = item.json.supplier_name;\n if (!groups[key]) {\n groups[key] = { supplier_name: key, items: [] };\n }\n groups[key].items.push(item.json);\n}\n\nreturn Object.values(groups).map(g => ({ json: g }));"
},
"typeVersion": 2
},
{
"id": "cb95acba-87bf-44a7-92b7-17b7a5656cb1",
"name": "Loop Over Suppliers",
"type": "n8n-nodes-base.splitInBatches",
"position": [
18160,
9040
],
"parameters": {
"options": {}
},
"typeVersion": 3
},
{
"id": "b459a004-db41-41f0-bcd2-52e9a8dcc2fd",
"name": "Complete Vendor Process",
"type": "n8n-nodes-base.noOp",
"position": [
18384,
9184
],
"parameters": {},
"typeVersion": 1
},
{
"id": "dd00ef4a-0682-45a2-a9d3-da9530d2f654",
"name": "Set Supplier Details",
"type": "n8n-nodes-base.set",
"position": [
18384,
8960
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "assign-001",
"name": "supplier_name",
"type": "string",
"value": "={{ $json.supplier_name }}"
},
{
"id": "assign-002",
"name": "supplier_email",
"type": "string",
"value": "={{ $json.items[0].supplier_email ?? '' }}"
},
{
"id": "assign-003",
"name": "items",
"type": "array",
"value": "={{ $json.items }}"
},
{
"id": "assign-004",
"name": "item_count",
"type": "number",
"value": "={{ $json.items.length }}"
},
{
"id": "assign-005",
"name": "items_markdown",
"type": "string",
"value": "={{ $json.items.map(i => '- **' + i.item_name + '** (ID: ' + i.item_id + '): current stock ' + i.current_stock + ', reorder level ' + i.reorder_level).join('\\n') }}"
},
{
"id": "assign-006",
"name": "log_date",
"type": "string",
"value": "={{ new Date().toLocaleDateString('fi-FI', {timeZone: 'Europe/Helsinki'}) }}"
},
{
"id": "assign-007",
"name": "log_doc_id",
"type": "string",
"value": "={{ $('Workflow Config').item.json.log_doc_id }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "3abdc09a-6ce0-42cd-ab2d-2f894db4ae62",
"name": "Build Email Draft",
"type": "@n8n/n8n-nodes-langchain.chainLlm",
"position": [
18736,
8960
],
"parameters": {
"text": "=Supplier: {{ $('Set Supplier Details').item.json.supplier_name }}\n\nItems to reorder ({{ $('Set Supplier Details').item.json.item_count }} total):\n{{ $('Set Supplier Details').item.json.items_markdown }}\n\nWrite a concise, professional reorder request email body in Markdown. Include a summary line at the top stating the total number of items. List each item with its current stock and reorder level. Close with a request for confirmation of receipt and expected delivery timeline.",
"messages": {
"messageValues": [
{
"type": "system",
"message": "You are a procurement assistant. Your task is to write professional reorder request email bodies in Markdown format. Return ONLY the email body text with no preamble, no greeting like 'Sure!', no explanation, and no closing remarks outside the email itself. Start directly with the email content."
}
]
},
"promptType": "define"
},
"typeVersion": 1.4
},
{
"id": "d48d0def-338e-4762-999b-f17a4d793354",
"name": "Claude Email Generation",
"type": "@n8n/n8n-nodes-langchain.lmChatAnthropic",
"position": [
18736,
9184
],
"parameters": {
"model": "claude-sonnet-4-6",
"options": {
"maxTokensToSample": 1024
}
},
"typeVersion": 1.2
},
{
"id": "413aeb87-319c-42d5-9978-36b3f8e43f38",
"name": "Convert Markdown to HTML",
"type": "n8n-nodes-base.markdown",
"position": [
19024,
8960
],
"parameters": {
"mode": "markdownToHtml",
"options": {},
"markdown": "={{ $json.text }}"
},
"typeVersion": 1
},
{
"id": "1ea620e2-13a7-4941-9902-a881d675178b",
"name": "Check Configured Doc ID",
"type": "n8n-nodes-base.if",
"position": [
19200,
8960
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 1,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "doc-id-set",
"operator": {
"type": "string",
"operation": "notEmpty"
},
"leftValue": "={{ $('Set Supplier Details').item.json.log_doc_id }}",
"rightValue": ""
}
]
}
},
"typeVersion": 2
},
{
"id": "2b115caa-1fb9-476f-93ed-ad72062b1b87",
"name": "Log to Google Docs",
"type": "n8n-nodes-base.googleDocs",
"position": [
19536,
8880
],
"parameters": {
"actionsUi": {
"actionFields": [
{
"text": "={{ '\\n' + $('Set Supplier Details').item.json.log_date + ' - Reorder sent to ' + $('Set Supplier Details').item.json.supplier_name + ' (' + $('Set Supplier Details').item.json.item_count + ' items)' }}",
"action": "insert"
}
]
},
"operation": "update",
"documentURL": "=={{'https://docs.google.com/document/d/' + $('Set Supplier Details').item.json.log_doc_id + '/edit'}}"
},
"credentials": {
"googleDocsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 2,
"continueOnFail": true
},
{
"id": "ef266923-6a98-43a0-b7eb-48b0d457054b",
"name": "Skip Logging",
"type": "n8n-nodes-base.noOp",
"position": [
19536,
9072
],
"parameters": {},
"typeVersion": 1
},
{
"id": "d7a85cba-af94-463d-a03f-43ccba0b06ef",
"name": "Send Reorder Email",
"type": "n8n-nodes-base.microsoftOutlook",
"position": [
20064,
9072
],
"parameters": {
"subject": "={{ 'Consolidated Reorder Request - ' + $('Set Supplier Details').item.json.supplier_name + ': ' + $('Set Supplier Details').item.json.item_count + ' item(s)' }}",
"bodyContent": "={{ $('Convert Markdown to HTML').item.json.data }}",
"toRecipients": "={{ $('Set Supplier Details').item.json.supplier_email }}",
"additionalFields": {
"bodyContentType": "html"
}
},
"typeVersion": 2,
"continueOnFail": true
},
{
"id": "a89cd126-840b-40f4-beeb-53ac2b8f0faa",
"name": "Send Error Alert",
"type": "n8n-nodes-base.microsoftOutlook",
"position": [
16688,
9664
],
"parameters": {
"subject": "=[n8n] Reorder workflow error - {{ $json.workflow?.name ?? 'AI Supplier Reorder' }}",
"bodyContent": "=<p><strong>Workflow:</strong> AI Supplier Reorder</p>\n<p><strong>Time:</strong> {{ new Date().toISOString() }}</p>\n<p><strong>Error:</strong> {{ $json.execution?.error?.message ?? JSON.stringify($json) }}</p>",
"toRecipients": "user@example.com",
"additionalFields": {
"bodyContentType": "html"
}
},
"typeVersion": 2
}
],
"active": false,
"settings": {
"binaryMode": "separate",
"executionOrder": "v1"
},
"versionId": "0cdeff1c-e822-4425-baec-0b4a9f01e05b",
"nodeGroups": [],
"connections": {
"Skip Logging": {
"main": [
[
{
"node": "Send Reorder Email",
"type": "main",
"index": 0
}
]
]
},
"When 7am Daily": {
"main": [
[
{
"node": "Workflow Config",
"type": "main",
"index": 0
}
]
]
},
"Workflow Config": {
"main": [
[
{
"node": "Query Snowflake DB",
"type": "main",
"index": 0
}
]
]
},
"Build Email Draft": {
"main": [
[
{
"node": "Convert Markdown to HTML",
"type": "main",
"index": 0
}
]
]
},
"Log to Google Docs": {
"main": [
[
{
"node": "Send Reorder Email",
"type": "main",
"index": 0
}
]
]
},
"Query Snowflake DB": {
"main": [
[
{
"node": "If Low Stock Exists",
"type": "main",
"index": 0
}
]
]
},
"Send Reorder Email": {
"main": [
[
{
"node": "Loop Over Suppliers",
"type": "main",
"index": 0
}
]
]
},
"If Low Stock Exists": {
"main": [
[
{
"node": "Group Items by Supplier",
"type": "main",
"index": 0
}
],
[
{
"node": "Pass Through",
"type": "main",
"index": 0
}
]
]
},
"Loop Over Suppliers": {
"main": [
[
{
"node": "Set Supplier Details",
"type": "main",
"index": 0
}
],
[
{
"node": "Complete Vendor Process",
"type": "main",
"index": 0
}
]
]
},
"Set Supplier Details": {
"main": [
[
{
"node": "Build Email Draft",
"type": "main",
"index": 0
}
]
]
},
"Check Configured Doc ID": {
"main": [
[
{
"node": "Log to Google Docs",
"type": "main",
"index": 0
}
],
[
{
"node": "Skip Logging",
"type": "main",
"index": 0
}
]
]
},
"Claude Email Generation": {
"ai_languageModel": [
[
{
"node": "Build Email Draft",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Group Items by Supplier": {
"main": [
[
{
"node": "Loop Over Suppliers",
"type": "main",
"index": 0
}
]
]
},
"Convert Markdown to HTML": {
"main": [
[
{
"node": "Check Configured Doc ID",
"type": "main",
"index": 0
}
]
]
}
}
}
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.
googleDocsOAuth2Api
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This workflow runs daily, queries Snowflake for items at or below their reorder level, and groups them by supplier. For each supplier, it uses Anthropic Claude to draft a reorder email, optionally appends details to a Google Docs log, and sends the email via Microsoft Outlook. A…
Source: https://n8n.io/workflows/16541/ — 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.
This workflow runs monthly to query KPI data from Google BigQuery, generates a narrative with Anthropic Claude, fills a Google Docs report template, exports it as a PDF, archives it to OneDrive, email
Template 7372. Uses googleSheets, outputParserStructured, lmChatAnthropic, n8n-nodes-serpapi. Scheduled trigger; 54 nodes.
This workflow empowers app developers and community management teams by automating the generation and posting of responses to user reviews on the Apple App Store. Designed to streamline the engagement
The Recap AI - Short Form News Script Generator. Uses httpRequest, s3, chainLlm, slack. Scheduled trigger; 42 nodes.
Categories Content Creation AI Automation Publishing Social Media