This workflow corresponds to n8n.io template #17528 — we link there as the canonical source.
This workflow follows the Chainllm → Gmail 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": "mhlC8SexrER2bYOk",
"name": "Supplier Lifecycle Compliance Tracker",
"tags": [],
"nodes": [
{
"id": "3a33f79d-0a83-4a2a-a7aa-7d17f7ef50be",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-160,
736
],
"parameters": {
"color": 7,
"width": 896,
"height": 496,
"content": "## 1. Data Ingestion & Tracking\nFetches all active supplier records from the Notion database, calculating compliance expiry deadlines, assigning urgency brackets, and filtering out recently alerted vendors."
},
"typeVersion": 1
},
{
"id": "412cba1f-83c2-418a-902d-bd95cd10a3a0",
"name": "Fetch Supplier Database",
"type": "n8n-nodes-base.notion",
"position": [
288,
928
],
"parameters": {
"options": {},
"resource": "databasePage",
"operation": "getAll",
"returnAll": true,
"databaseId": {
"__rl": true,
"mode": "list",
"value": "38731eba-a729-8029-a300-c2fc6ad2d476",
"cachedResultUrl": "https://app.notion.com/p/38731ebaa7298029a300c2fc6ad2d476",
"cachedResultName": "supplier_compliance_data"
}
},
"typeVersion": 2.2
},
{
"id": "3780b7be-ea4d-406d-8ef7-29bb42989607",
"name": "Calculate Expiry Timelines",
"type": "n8n-nodes-base.code",
"position": [
512,
928
],
"parameters": {
"jsCode": "// Get all items passed from the Notion trigger node\nconst items = $input.all();\nconst output = [];\n\n// Get today's date (at midnight to keep date math precise)\nconst today = new Date();\ntoday.setHours(0, 0, 0, 0);\n\nfor (let item of items) {\n const data = item.json;\n \n const supplierName = data[\"property_supplier_name\"] || data[\"name\"];\n const status = data[\"property_status\"];\n const contactEmail = data[\"property_contact_email\"];\n const certType = data[\"property_certification_type\"];\n \n // Extracting from Notion's nested object format safely\n const expiryObj = data[\"property_certification_expiry\"];\n const expiryStr = expiryObj && typeof expiryObj === 'object' ? expiryObj.start : expiryObj;\n \n const lastAlertObj = data[\"property_last_compliance_alert\"];\n const lastAlertStr = lastAlertObj && typeof lastAlertObj === 'object' ? lastAlertObj.start : lastAlertObj;\n\n // 1. Skip if supplier is explicitly deactivated or manually handled\n if (status === 'Offboarded' || status === 'In Requalification') {\n continue;\n }\n\n // 2. Edge Case Guard: Handle truly missing expiry dates\n if (!expiryStr) {\n output.push({\n json: {\n ...data,\n daysRemaining: null,\n actionRequired: \"ESCALATE_MISSING_DATA\",\n reason: `Supplier ${supplierName} is active but has no recorded expiry date.`\n }\n });\n continue;\n }\n\n const expiryDate = new Date(expiryStr);\n expiryDate.setHours(0, 0, 0, 0);\n\n // Calculate the difference in days\n const timeDiff = expiryDate.getTime() - today.getTime();\n const daysRemaining = Math.ceil(timeDiff / (1000 * 60 * 60 * 24));\n\n let actionRequired = \"IGNORE_COMPLIANT\"; \n let reason = \"Supplier is fully compliant.\";\n\n // Anti-Spam Guard: Check if we alerted them within the last 14 days\n let recentlyAlerted = false;\n if (lastAlertStr) {\n const lastAlertDate = new Date(lastAlertStr);\n const alertAgeDiff = today.getTime() - lastAlertDate.getTime();\n const daysSinceAlert = Math.floor(alertAgeDiff / (1000 * 60 * 60 * 24));\n if (daysSinceAlert <= 14) {\n recentlyAlerted = true;\n }\n }\n\n // 3. Bracket Assignment & Logic Rules\n if (daysRemaining < 0) {\n if (recentlyAlerted) {\n actionRequired = \"IGNORE_ALREADY_NOTIFIED\";\n reason = `Expired (${Math.abs(daysRemaining)} days ago), but an alert was sent recently. Anti-spam engaged.`;\n } else {\n actionRequired = \"CRITICAL_BREACH\";\n reason = `CRITICAL: Certification expired ${Math.abs(daysRemaining)} days ago. Escalation required.`;\n }\n } else if (daysRemaining <= 14) {\n if (recentlyAlerted) {\n actionRequired = \"IGNORE_ALREADY_NOTIFIED\";\n reason = `Expiring soon (${daysRemaining} days remaining), but already alerted recently.`;\n } else {\n actionRequired = \"ALERT_14_DAYS\";\n reason = `URGENT: Certification expires in ${daysRemaining} days. Needs high-priority alert.`;\n }\n } else if (daysRemaining <= 30) {\n if (recentlyAlerted) {\n actionRequired = \"IGNORE_ALREADY_NOTIFIED\";\n reason = `Expiring in 30-day window, but already alerted recently.`;\n } else {\n actionRequired = \"ALERT_30_DAYS\";\n reason = `WARNING: Compliance routine renewal window open (${daysRemaining} days remaining).`;\n }\n }\n\n // Filter out the non-actionable elements to prevent unnecessary node executions down the line\n if (actionRequired !== \"IGNORE_COMPLIANT\" && actionRequired !== \"IGNORE_ALREADY_NOTIFIED\") {\n output.push({\n json: {\n ...data,\n daysRemaining: daysRemaining,\n actionRequired: actionRequired,\n reason: reason\n }\n });\n }\n}\n\nreturn output;"
},
"typeVersion": 2
},
{
"id": "556356f4-53e8-4c1c-9d82-710365e7bf7e",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
864,
768
],
"parameters": {
"color": 7,
"width": 1664,
"height": 688,
"content": "## 2. AI Content Generation & Loop Closure\nIterates through records, sets initial variables, stamps the database to prevent duplicate alerts, generates AI communications, buffers API rates, and formats the output."
},
"typeVersion": 1
},
{
"id": "ef888e18-4190-453f-9a44-29aa3f3e84b8",
"name": "Loop Supplier Records",
"type": "n8n-nodes-base.splitInBatches",
"position": [
992,
928
],
"parameters": {
"options": {}
},
"typeVersion": 3
},
{
"id": "f9d2ead9-17a6-499e-87bc-264cf6269dd1",
"name": "Prepare AI Prompt Data",
"type": "n8n-nodes-base.set",
"position": [
1280,
1056
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "b324552a-27ed-4e27-827d-ea08e4065c3e",
"name": "id",
"type": "string",
"value": "={{ $json.id.split(\"-\").join(\"\") }}"
},
{
"id": "82e4a41b-553f-47d2-92a9-f6b0917ec127",
"name": "name",
"type": "string",
"value": "={{ $json.name }}"
},
{
"id": "bbe54f2a-0a23-4629-ba4a-d16e00fb127f",
"name": "property_contact_email",
"type": "string",
"value": "={{ $json.property_contact_email }}"
},
{
"id": "2a095290-b979-4826-80da-23e012f8379f",
"name": "property_certification_type",
"type": "string",
"value": "={{ $json.property_certification_type }}"
},
{
"id": "4a8867e6-4b19-440f-a110-9400e47495b9",
"name": "reason",
"type": "string",
"value": "={{ $json.reason }}"
},
{
"id": "6538b6ad-38aa-4117-b62e-088862cda377",
"name": "actionRequired",
"type": "string",
"value": "={{ $json.actionRequired }}"
},
{
"id": "886e2905-9539-460b-85d2-d9c6a90c3451",
"name": "property_certification_expiry",
"type": "string",
"value": "={{ $json.property_certification_expiry }}"
},
{
"id": "ac76fb9f-f444-4a22-863c-c49b9a950cac",
"name": "daysRemaining",
"type": "string",
"value": "={{ $json.daysRemaining }}"
},
{
"id": "0e51a6d3-b3cc-44c2-9253-a69e19266d18",
"name": "property_status",
"type": "string",
"value": "={{ $json.property_status }}"
},
{
"id": "3efa478a-8909-4d95-800d-8a9d4fba87de",
"name": "property_notes_context",
"type": "string",
"value": "={{ $json.property_notes_context }}"
}
]
},
"includeOtherFields": true
},
"typeVersion": 3.4
},
{
"id": "b7e355d9-6ce9-4219-b085-6721c45f3fa5",
"name": "Stamp Last Alert Date",
"type": "n8n-nodes-base.notion",
"position": [
1472,
1056
],
"parameters": {
"pageId": {
"__rl": true,
"mode": "id",
"value": "={{ $json.id }}"
},
"simple": "=",
"options": {},
"resource": "databasePage",
"operation": "update",
"propertiesUi": {
"propertyValues": [
{
"key": "Last Compliance Alert|date",
"date": "={{ $now.format('MM-DD') }}",
"timezone": "Asia/Kolkata"
}
]
}
},
"typeVersion": 2.2
},
{
"id": "76b1a8d4-2c24-498d-a08c-578892d52784",
"name": "Generate Communications",
"type": "@n8n/n8n-nodes-langchain.chainLlm",
"position": [
1648,
1056
],
"parameters": {
"text": "=Please generate the required communications for the following supplier:\n\n- Supplier Name: {{ $('Prepare AI Prompt Data').item.json.name }}\n- Contact Email: {{ $('Prepare AI Prompt Data').item.json.property_contact_email }}\n- Certificate Type Missing/Expiring: {{ $('Prepare AI Prompt Data').item.json.property_certification_expiry }}\n- Days Remaining until/since expiry: {{ $('Prepare AI Prompt Data').item.json.daysRemaining }} days\n- Current System Urgency Bracket: {{ $('Prepare AI Prompt Data').item.json.actionRequired }}\n- System Reason: {{ $('Prepare AI Prompt Data').item.json.reason }}\n- id: {{ $json.id }}\n\nRemember, return your response strictly as a JSON object matching this structure:\n{\n \"emailBody\": \"...\",\n \"slackMessage\": \"...\",\n \"email\":\"...\",\n \"id\":\"...\"\n}",
"batching": {},
"messages": {
"messageValues": [
{
"message": "You are an automated Supplier Compliance Watchdog for our Procurement Team. Your job is to look at a supplier's compliance status and generate two specific messaging outputs based on how close they are to their certification expiration deadline. You must ALWAYS output your response as a valid JSON object with exactly three keys: 1. \"emailBody\": A well-structured, professional, markdown-formatted email to be sent to the supplier contact. 2. \"slackMessage\": A short, urgent, block-style text notice for internal procurement staff. Tone Guidelines: - If actionRequired is ALERT_30_DAYS: Keep the email helpful, professional, and routine. - If actionRequired is ALERT_14_DAYS: Make the email urgent, emphasizing that disruptions to procurement may occur if documentation is missed. - If actionRequired is CRITICAL_BREACH: The email should be highly urgent, noting that compliance is past due. Do not include markdown code block formatting (like ```json) inside your text response; output raw JSON text directly, 3. \"email\": supplier's email, \"id\": supplier's id."
}
]
},
"promptType": "define",
"hasOutputParser": true
},
"typeVersion": 1.9
},
{
"id": "6999dfa7-934b-41c1-b301-26d96c0b6985",
"name": "Groq Llama 3.3 Model",
"type": "@n8n/n8n-nodes-langchain.lmChatGroq",
"position": [
1648,
1280
],
"parameters": {
"model": "llama-3.3-70b-versatile",
"options": {}
},
"typeVersion": 1
},
{
"id": "4085610c-b00c-4409-b883-5e4d991e74dd",
"name": "JSON Output Parser",
"type": "@n8n/n8n-nodes-langchain.outputParserStructured",
"onError": "continueRegularOutput",
"position": [
1792,
1280
],
"parameters": {
"autoFix": true,
"schemaType": "manual",
"inputSchema": "{\n \"type\": \"object\",\n \"properties\": {\n \"emailBody\": {\n \"type\": \"string\",\n \"description\": \"A well-structured, professional, markdown-formatted email text to be sent to the supplier contact. Tone varies based on urgency.\"\n },\n \"slackMessage\": {\n \"type\": \"string\",\n \"description\": \"A short, urgent, block-style text notice for the internal procurement staff channel.\"\n },\n \"email\": {\n \"type\": \"string\",\n \"description\": \"The supplier's contact email address.\"\n },\n \"id\": {\n \"type\": \"string\",\n \"description\": \"The supplier's id\"\n }\n },\n \"required\": [\n \"emailBody\",\n \"slackMessage\",\n \"email\",\n \"id\"\n ]\n}"
},
"typeVersion": 1.3
},
{
"id": "eeb0a48a-3143-4af3-880a-1aa4d168b4af",
"name": "API Rate Limit Buffer",
"type": "n8n-nodes-base.wait",
"position": [
1968,
1056
],
"parameters": {},
"typeVersion": 1.1
},
{
"id": "f0ea48e9-d00f-4438-881b-68646392ea96",
"name": "Format Loop Output",
"type": "n8n-nodes-base.set",
"position": [
2176,
1056
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "593e1fc7-4826-4054-9ca4-d4f09810a3a3",
"name": "id",
"type": "string",
"value": "={{ $('Prepare AI Prompt Data').item.json.id }}"
},
{
"id": "eb6acb92-d740-4ebc-9c7f-e73bb517bfa3",
"name": "name",
"type": "string",
"value": "={{ $('Prepare AI Prompt Data').item.json.name }}"
},
{
"id": "a7b299f6-669a-4306-a220-6853fe038135",
"name": "property_certification_expiry",
"type": "string",
"value": "={{ $('Prepare AI Prompt Data').item.json.property_certification_expiry }}"
},
{
"id": "b52dcaa0-0c7e-4b1c-a313-826cfa063546",
"name": "property_status",
"type": "string",
"value": "={{ $('Prepare AI Prompt Data').item.json.property_status }}"
},
{
"id": "097f76c6-5775-4ec8-b74a-4809f172cd05",
"name": "property_contact_email",
"type": "string",
"value": "={{ $('Prepare AI Prompt Data').item.json.property_contact_email }}"
},
{
"id": "d71dcf81-e5bf-470d-bf8a-e47cd391c7ed",
"name": "property_certification_type",
"type": "string",
"value": "={{ $('Prepare AI Prompt Data').item.json.property_certification_type }}"
},
{
"id": "0a824c23-4706-4ca0-8cd6-06ba4373c4f8",
"name": "daysRemaining",
"type": "string",
"value": "={{ $('Prepare AI Prompt Data').item.json.daysRemaining }}"
},
{
"id": "11f76bff-bf19-4a6c-bb17-4605134e9c52",
"name": "property_notes_context",
"type": "string",
"value": "={{ $('Prepare AI Prompt Data').item.json.property_notes_context }}"
},
{
"id": "5c1249fb-9a1c-4e7a-927e-5b77f2942423",
"name": "actionRequired",
"type": "string",
"value": "={{ $('Prepare AI Prompt Data').item.json.actionRequired }}"
},
{
"id": "ae860cf7-e557-4f6b-bd91-823564d98173",
"name": "reason",
"type": "string",
"value": "={{ $('Prepare AI Prompt Data').item.json.reason }}"
},
{
"id": "360c507c-b75b-4d4b-9267-d8756b89e6c3",
"name": "emailBody",
"type": "string",
"value": "={{ $json.output.emailBody }}"
},
{
"id": "d780e2cf-b444-4681-97ca-692df51a7080",
"name": "slackMessage",
"type": "string",
"value": "={{ $json.output.slackMessage }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "707a85c3-0a87-416c-af4c-b479414ea484",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
1200,
48
],
"parameters": {
"color": 7,
"width": 1040,
"height": 560,
"content": "## 3. Routing & Standard Notifications\nFormats the parsed AI data and routes suppliers based on urgency, dispatching standard email reminders and internal Slack updates for upcoming expirations."
},
"typeVersion": 1
},
{
"id": "09dc6097-8efa-47f1-9f5c-b00a4b9d5aef",
"name": "Format Routing Data",
"type": "n8n-nodes-base.set",
"position": [
1360,
304
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "f1abcff2-4c2a-4410-b8bb-12006360deed",
"name": "emailBody",
"type": "string",
"value": "={{ $json.emailBody }}"
},
{
"id": "aef6ceba-7563-4e2f-8160-f65557a41f86",
"name": "slackMessage",
"type": "string",
"value": "={{ $json.slackMessage }}"
},
{
"id": "91672978-1ea4-42f3-b7a4-65525882fffa",
"name": "email",
"type": "string",
"value": "={{ $json.property_contact_email }}"
},
{
"id": "694b7e22-1818-43b7-994a-abfdb863d010",
"name": "name",
"type": "string",
"value": "={{ $json.name }}"
},
{
"id": "041348bc-02e6-4f05-bb39-2b1fac531a9e",
"name": "id",
"type": "string",
"value": "={{ $json.id }}"
},
{
"id": "672ae281-9d25-4eca-9eb9-1473ae0afb8c",
"name": "property_certification_expiry",
"type": "string",
"value": "={{ $json.property_certification_expiry }}"
},
{
"id": "77fad5c4-950d-4d0a-88bc-37ea2d84b9c1",
"name": "property_status",
"type": "string",
"value": "={{ $json.property_status }}"
},
{
"id": "744a6aa0-8207-4dee-9916-d21c47e92b83",
"name": "property_certification_type",
"type": "string",
"value": "={{ $json.property_certification_type }}"
},
{
"id": "7f36623c-450e-4bf0-a3cd-28df01d7eae6",
"name": "daysRemaining",
"type": "string",
"value": "={{ $json.daysRemaining }}"
},
{
"id": "7a859766-8b2e-49ec-bc25-2f652afa1b0a",
"name": "property_notes_context",
"type": "string",
"value": "={{ $json.property_notes_context }}"
},
{
"id": "e10a7203-20e3-4+1234567890f15078f1f",
"name": "actionRequired",
"type": "string",
"value": "={{ $json.actionRequired }}"
},
{
"id": "8a6d707e-a8a4-4061-8267-f0b782e07598",
"name": "reason",
"type": "string",
"value": "={{ $json.reason }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "8e616854-5779-4b7a-bd02-19e1ea020735",
"name": "Urgency Routing Engine",
"type": "n8n-nodes-base.switch",
"position": [
1616,
272
],
"parameters": {
"rules": {
"values": [
{
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "e30c173e-cd75-440d-bf3c-31cb4381e2b6",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.actionRequired }}",
"rightValue": "ALERT_30_DAYS"
}
]
}
},
{
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "9700f607-1261-4564-b54e-b530a9d455d7",
"operator": {
"name": "filter.operator.equals",
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.actionRequired }}",
"rightValue": "ALERT_14_DAYS"
}
]
}
},
{
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "3da4a91a-3116-4ca6-846c-c1a7c8e0e041",
"operator": {
"name": "filter.operator.equals",
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.actionRequired }}",
"rightValue": "CRITICAL_BREACH"
}
]
}
},
{
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "a07ea22e-c930-4084-a7c0-2af710098f32",
"operator": {
"name": "filter.operator.equals",
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.actionRequired }}",
"rightValue": "ESCALATE_MISSING_DATA"
}
]
}
}
]
},
"options": {}
},
"typeVersion": 3.4
},
{
"id": "f6865f52-5889-467d-bdbe-b1a9f0219e39",
"name": "Standard Renewal Notice",
"type": "n8n-nodes-base.gmail",
"position": [
1936,
208
],
"parameters": {
"sendTo": "={{ $json.email }}",
"message": "=<!DOCTYPE html>\n<html>\n<head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <style>\n body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background-color: #f4f6f8; color: #333333; margin: 0; padding: 0; }\n .email-container { max-width: 600px; margin: 20px auto; background: #ffffff; border-radius: 8px; overflow: hidden; box-shadow: 0 4px 10px rgba(0,0,0,0.05); border: 1px solid #e1e4e8; }\n \n /* DYNAMIC BANNER BACKGROUND COLOR */\n .alert-banner { \n background-color:{{ $json.actionRequired === 'CRITICAL_BREACH' ? '#b52b27' : ($json.actionRequired === 'ALERT_14_DAYS' ? '#e65100' : ($json.actionRequired === 'ALERT_30_DAYS' ? '#2f55d4' : '#6a1b9a')) }}; \n color: #ffffff; padding: 16px 24px; font-size: 14px; font-weight: bold; text-transform: uppercase; letter-spacing: 0.05em; \n }\n \n .email-body { padding: 32px 24px; }\n .status-card { background-color: #f8f9fa; border-left: 4px solid {{ $json.actionRequired === 'CRITICAL_BREACH' ? '#b52b27' : ($json.actionRequired === 'ALERT_14_DAYS' ? '#e65100' : ($json.actionRequired === 'ALERT_30_DAYS' ? '#2f55d4' : '#6a1b9a')) }}; padding: 16px; margin-bottom: 24px; border-radius: 0 4px 4px 0; }\n .status-row { margin-bottom: 8px; font-size: 14px; }\n .status-label { font-weight: 600; color: #666666; display: inline-block; width: 140px; }\n .status-value { color: #1a1a1a; font-weight: 500; }\n p { font-size: 15px; line-height: 1.6; color: #4a4a4a; margin-top: 0; margin-bottom: 16px; }\n .email-footer { background-color: #f8f9fa; padding: 24px; text-align: center; font-size: 12px; color: #888888; border-top: 1px solid #e1e4e8; }\n </style>\n</head>\n<body>\n\n <div class=\"email-container\">\n <!-- DYNAMIC BANNER TEXT -->\n <div class=\"alert-banner\">\n {{ $json.actionRequired === 'CRITICAL_BREACH' ? ' CRITICAL COMPLIANCE BREACH NOTICE' : ($json.actionRequired === 'ALERT_14_DAYS' ? ' URGENT: REQUALIFICATION COUNTDOWN' : ($json.actionRequired === 'ALERT_30_DAYS' ? ' ROUTINE RENEWAL REMINDER' : ' ACTION REQUIRED: PROFILE UPDATE')) }}\n </div>\n\n <div class=\"email-body\">\n <!-- MAIN BODY TEXT (Converts OpenAI text newlines to HTML paragraphs cleanly) -->\n <p>{{ $('Format Routing Data').item.json.emailBody.replace(/\\n/g, '<br>') }}</p>\n\n <!-- AUTOMATED METADATA CARD -->\n <div class=\"status-card\">\n <div class=\"status-row\">\n <span class=\"status-label\">Supplier Name:</span>\n <span class=\"status-value\">{{ $('Format Routing Data').item.json.name }}</span>\n </div>\n <div class=\"status-row\">\n <span class=\"status-label\">Requirement:</span>\n <span class=\"status-value\">{{ $json.property_certification_type }}</span>\n </div>\n <div class=\"status-row\">\n <span class=\"status-label\">Current Status:</span>\n <span class=\"status-value\"><strong>{{ $json.reason }}</strong></span>\n </div>\n </div>\n \n <p>If you have any questions regarding this assessment or believe our core registry metadata is outdated, please reply directly to this thread to connect with our operations team.</p>\n </div>\n\n <div class=\"email-footer\">\n This is an automated tracking notification managed by our Global Procurement Operations Framework.<br>\n To submit documents directly, please utilize your designated supplier portal asset link.\n </div>\n </div>\n\n</body>\n</html>",
"options": {},
"subject": "=Action Required: {{ $json.property_certification_type }} Compliance for {{ $json.name }}"
},
"typeVersion": 2.2
},
{
"id": "c7420c06-c747-4667-ab2f-09292dee36cb",
"name": "Routine Internal Alert",
"type": "n8n-nodes-base.slack",
"position": [
1936,
400
],
"parameters": {
"text": "={{ $json.slackMessage }}",
"select": "channel",
"channelId": {
"__rl": true,
"mode": "list",
"value": "C0AQS47TGQ0",
"cachedResultName": "all-dropbox-note-sync"
},
"otherOptions": {},
"authentication": "oAuth2"
},
"typeVersion": 2.4
},
{
"id": "d0a72600-6fec-47e0-839f-b48aee6ef700",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
2384,
-16
],
"parameters": {
"color": 7,
"width": 1088,
"height": 736,
"content": "## 4. Critical Breach Escalation \nHandles severe compliance breaches by formatting escalation data, automatically suspending the vendor in Notion, and sending urgent warnings to all stakeholders."
},
"typeVersion": 1
},
{
"id": "8aa76361-667f-40b4-b4d4-8ab338e9d56b",
"name": "Prepare Escalation Data",
"type": "n8n-nodes-base.set",
"position": [
2576,
320
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "bdd5ac98-429f-4da8-b4b5-f3ad838ebd6e",
"name": "emailBody",
"type": "string",
"value": "={{ $json.emailBody }}"
},
{
"id": "bdc772ca-54a9-42e5-a266-f120238b26dd",
"name": "slackMessage",
"type": "string",
"value": "={{ $json.slackMessage }}"
},
{
"id": "f3fc6a74-b6aa-45c8-8653-baa3f0bbe33c",
"name": "email",
"type": "string",
"value": "={{ $json.email }}"
},
{
"id": "59b91b91-f8a5-45db-a637-b56a551e894c",
"name": "id",
"type": "string",
"value": "={{ $json.id.split(\"-\").join(\"\") }}"
},
{
"id": "fb6b3ec1-661b-4b11-8b7f-318d8bbad170",
"name": "name",
"type": "string",
"value": "={{ $json.name }}"
}
]
},
"includeOtherFields": true
},
"typeVersion": 3.4
},
{
"id": "2057c5ae-d902-4dca-84f3-b9d7be3ba892",
"name": "Final Suspension Warning",
"type": "n8n-nodes-base.gmail",
"position": [
2896,
144
],
"parameters": {
"sendTo": "={{ $json.email }}",
"message": "=<!DOCTYPE html>\n<html>\n<body style=\"font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif; background-color: #f4f6f8; padding: 20px;\">\n\n <div style=\"max-width: 600px; margin: 0 auto; background: #ffffff; border-radius: 8px; border: 1px solid #e1e4e8; overflow: hidden;\">\n \n <div style=\"background-color: #b52b27; color: #ffffff; padding: 16px 24px; font-size: 14px; font-weight: bold; text-transform: uppercase; letter-spacing: 0.05em;\">\n ACCOUNT SUSPENSION NOTICE\n </div>\n\n <div style=\"padding: 32px 24px; color: #333333;\">\n <p style=\"font-size: 16px; margin-top: 0;\">Dear <strong>{{ $json.name }}</strong> Team,</p>\n \n <p style=\"font-size: 15px; line-height: 1.6;\">This is an official automated notice that your active supplier status has been temporarily suspended due to a critical compliance breach.</p>\n\n <div style=\"background-color: #fdf2f2; border-left: 4px solid #b52b27; padding: 16px; margin: 24px 0; border-radius: 0 4px 4px 0;\">\n <p style=\"margin: 0 0 8px 0; font-size: 14px;\"><strong>Missing Requirement:</strong> {{ $json.property_certification_type }}</p>\n <p style=\"margin: 0; font-size: 14px; color: #b52b27;\"><strong>Status:</strong> Expired {{ Math.abs($json.daysRemaining) }} days ago.</p>\n </div>\n\n <p style=\"font-size: 15px; line-height: 1.6;\"><strong>What this means:</strong> Until this documentation is updated and verified, we cannot process new purchase orders, issue payments, or continue standard procurement operations with your company.</p>\n \n <div style=\"text-align: center; margin: 32px 0;\">\n <a href=\"[INSERT YOUR SECURE UPLOAD LINK HERE]\" style=\"background-color: #b52b27; color: #ffffff; text-decoration: none; padding: 12px 28px; font-size: 15px; font-weight: bold; border-radius: 4px; display: inline-block;\">Upload Renewed Documentation</a>\n </div>\n\n <p style=\"font-size: 14px; color: #666666; margin-bottom: 0;\">If you believe this is an error or have already initiated the audit process, please reply directly to this email to sync with our Risk Operations team.</p>\n </div>\n </div>\n\n</body>\n</html>",
"options": {},
"subject": "=URGENT NOTICE OF SUSPENSION: {{ $json.property_certification_type }} Expired"
},
"typeVersion": 2.2
},
{
"id": "5900551d-d1d9-4d50-99f6-700172d78771",
"name": "Risk Team Escalation",
"type": "n8n-nodes-base.slack",
"position": [
2896,
512
],
"parameters": {
"text": "=*VENDOR SUSPENDED: CRITICAL COMPLIANCE BREACH*\n<!here> \n*Supplier:* {{ $json.name }}\n*Missing Requirement:* {{ $json.property_certification_type }}\n*Severity:* Expired {{ Math.abs($json.daysRemaining) }} days ago.\n\n*Action Taken:* The automated watchdog has shifted their Notion status to 'In Requalification' and dispatched a final warning email requesting an immediate document upload.",
"select": "channel",
"channelId": {
"__rl": true,
"mode": "list",
"value": "C0AQS47TGQ0",
"cachedResultName": "all-dropbox-note-sync"
},
"otherOptions": {},
"authentication": "oAuth2"
},
"typeVersion": 2.4
},
{
"id": "434c9262-7356-4a23-9e1f-5dc4229c9cc8",
"name": "Suspend Vendor Status",
"type": "n8n-nodes-base.notion",
"position": [
2896,
320
],
"parameters": {
"pageId": {
"__rl": true,
"mode": "id",
"value": "={{ $json.id }}"
},
"options": {},
"resource": "databasePage",
"operation": "update",
"propertiesUi": {
"propertyValues": [
{
"key": "Status|select",
"selectValue": "In Requalification"
}
]
}
},
"typeVersion": 2.2
},
{
"id": "b66fa0de-c4b2-4c8b-9f58-1e6efe2bfc91",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
-256,
-176
],
"parameters": {
"width": 1296,
"height": 800,
"content": "## Workflow Overview: Supplier Lifecycle Compliance Tracker\n\nThis workflow acts as an automated **Compliance Watchdog** for the procurement process. It monitors supplier lifecycle events by analyzing certification expiry dates stored in a Notion master database. By automatically calculating urgency brackets, predicting upcoming gaps, generating AI-tailored communications, and executing a \"kill switch\" for non-compliant vendors, it ensures your supply chain remains uninterrupted and strictly aligned with regulatory standards.\n\n## How it works\n\nThis workflow acts as an automated **Compliance Watchdog** for your risk and procurement departments. It runs entirely hands-free on a daily schedule, fetching active supplier records and mathematically calculating how close each vendor is to their certification expiration deadline.\nIf a supplier is approaching a 14-day or 30-day renewal window, the system uses an LLM to draft and send highly personalized, context-aware reminder emails while logging the alert. If a critical breach is detected (an expired certificate), the workflow acts as a fail-safe: it instantly suspends the vendor in Notion to block new purchase orders, alerts your internal risk team via Slack, and emails the supplier a final rejection notice demanding immediate document upload.\n\n## Setup Steps\n\n**Daily Schedule Trigger** \u2014 Start the workflow automatically every morning to audit the database.\n**Fetch Supplier Database** \u2014 Retrieve all active supplier profiles and certification timelines from Notion.\n**Calculate Expiry Timelines** \u2014 Execute custom code to categorize suppliers into urgency brackets and filter out recently alerted vendors to prevent email spam.\n**Prepare AI Prompt Data** \u2014 Format the expiring supplier data into a clean structure for the language model.\n**Stamp Last Alert Date** \u2014 Update the vendor's Notion profile with today's date to engage the anti-spam lock and close the loop.\n**AI Communications Generator** \u2014 Use a Groq-powered LLM to dynamically draft personalized, markdown-formatted emails and internal Slack updates.\n**Format & Route Data** \u2014 Parse the AI's JSON output and route the supplier down one of four specific action paths based on their urgency level.\n**Routine Renewal Notices** \u2014 Dispatch standard 14-day and 30-day warning emails via Gmail and notify the procurement Slack channel.\n**Suspend Vendor Status** \u2014 Automatically flip the vendor's Notion status to 'In Requalification' if a critical historical breach is detected.\n**Critical Escalation Alerts** \u2014 Send a final suspension warning to the vendor and a high-priority @here alert to the internal risk team."
},
"typeVersion": 1
},
{
"id": "5265ad6d-7566-406d-a8d6-eb52da50d261",
"name": "Schedule Trigger",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
48,
928
],
"parameters": {
"rule": {
"interval": [
{
"triggerAtHour": 8
}
]
}
},
"typeVersion": 1.3
}
],
"active": false,
"settings": {
"binaryMode": "separate",
"availableInMCP": false,
"executionOrder": "v1"
},
"versionId": "f4a49a5d-d204-455d-ac63-0faffe496a6b",
"nodeGroups": [],
"connections": {
"Schedule Trigger": {
"main": [
[
{
"node": "Fetch Supplier Database",
"type": "main",
"index": 0
}
]
]
},
"Format Loop Output": {
"main": [
[
{
"node": "Loop Supplier Records",
"type": "main",
"index": 0
}
]
]
},
"JSON Output Parser": {
"ai_outputParser": [
[
{
"node": "Generate Communications",
"type": "ai_outputParser",
"index": 0
}
]
]
},
"Format Routing Data": {
"main": [
[
{
"node": "Urgency Routing Engine",
"type": "main",
"index": 0
}
]
]
},
"Groq Llama 3.3 Model": {
"ai_languageModel": [
[
{
"node": "Generate Communications",
"type": "ai_languageModel",
"index": 0
},
{
"node": "JSON Output Parser",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"API Rate Limit Buffer": {
"main": [
[
{
"node": "Format Loop Output",
"type": "main",
"index": 0
}
]
]
},
"Loop Supplier Records": {
"main": [
[
{
"node": "Format Routing Data",
"type": "main",
"index": 0
}
],
[
{
"node": "Prepare AI Prompt Data",
"type": "main",
"index": 0
}
]
]
},
"Stamp Last Alert Date": {
"main": [
[
{
"node": "Generate Communications",
"type": "main",
"index": 0
}
]
]
},
"Prepare AI Prompt Data": {
"main": [
[
{
"node": "Stamp Last Alert Date",
"type": "main",
"index": 0
}
]
]
},
"Urgency Routing Engine": {
"main": [
[
{
"node": "Standard Renewal Notice",
"type": "main",
"index": 0
},
{
"node": "Routine Internal Alert",
"type": "main",
"index": 0
}
],
[
{
"node": "Standard Renewal Notice",
"type": "main",
"index": 0
},
{
"node": "Routine Internal Alert",
"type": "main",
"index": 0
}
],
[
{
"node": "Routine Internal Alert",
"type": "main",
"index": 0
},
{
"node": "Prepare Escalation Data",
"type": "main",
"index": 0
}
],
[
{
"node": "Routine Internal Alert",
"type": "main",
"index": 0
}
]
]
},
"Fetch Supplier Database": {
"main": [
[
{
"node": "Calculate Expiry Timelines",
"type": "main",
"index": 0
}
]
]
},
"Generate Communications": {
"main": [
[
{
"node": "API Rate Limit Buffer",
"type": "main",
"index": 0
}
]
]
},
"Prepare Escalation Data": {
"main": [
[
{
"node": "Suspend Vendor Status",
"type": "main",
"index": 0
},
{
"node": "Risk Team Escalation",
"type": "main",
"index": 0
},
{
"node": "Final Suspension Warning",
"type": "main",
"index": 0
}
]
]
},
"Calculate Expiry Timelines": {
"main": [
[
{
"node": "Loop Supplier Records",
"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 workflow runs daily to audit a Notion supplier compliance database, calculates certification expiry urgency, uses Groq (Llama 3.3 via LangChain) to generate supplier emails and internal Slack messages, and then sends notifications through Gmail and Slack while updating…
Source: https://n8n.io/workflows/17528/ — 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.
Doc Processing. Uses chainLlm, lmChatGroq, googleDrive, googleSheets. Scheduled trigger; 39 nodes.
This workflow watches a Google Drive folder for newly uploaded contract PDFs, extracts key clauses with Groq-hosted LLMs, compares them to standard clauses stored in Notion, generates a structured ris
This scheduled workflow pulls last week’s Salesforce opportunities, tasks, and events for a specific rep, computes activity and pipeline health metrics, uses Groq (LLM) to generate coaching insights,
This workflow is a comprehensive automation engine that bridges the gap between raw client data and expert-level financial advice. Upon receiving a new onboarding form from Google Sheets, the system f
This workflow is a high-precision financial intelligence engine that monitors macroeconomic news to identify high-impact trading opportunities. It retrieves real-time data via SerpAPI, processes it th