AutomationFlowsAI & RAG › AI Content Review: Slack & Gmail Escalation

AI Content Review: Slack & Gmail Escalation

Original n8n title: Production AI Playbook: Human Oversight (exercise 3)

ByElvis Sarvia @elvissaravia on n8n.io

Route AI-generated content to reviewers on Slack or email, with automatic escalation if nobody responds. This template demonstrates a full multi-channel review workflow with timeout handling.

Event trigger★★★★☆ complexityAI-powered15 nodesForm TriggerAgentOpenAI ChatSlackGmail
AI & RAG Trigger: Event Nodes: 15 Complexity: ★★★★☆ AI nodes: yes Added:

This workflow corresponds to n8n.io template #13849 — we link there as the canonical source.

This workflow follows the Agent → Form 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 →

Download .json
{
  "nodes": [
    {
      "id": "d6df5e4d-1ea2-41d4-b13b-08a0c062389a",
      "name": "On form submission1",
      "type": "n8n-nodes-base.formTrigger",
      "position": [
        -1472,
        1296
      ],
      "parameters": {
        "options": {},
        "formTitle": "Content Approval Request",
        "formFields": {
          "values": [
            {
              "fieldType": "textarea",
              "fieldLabel": "Content Body"
            },
            {
              "fieldType": "dropdown",
              "fieldLabel": "Approval Channel",
              "fieldOptions": {
                "values": [
                  {
                    "option": "slack"
                  },
                  {
                    "option": "email"
                  }
                ]
              }
            }
          ]
        },
        "formDescription": "Submit AI-generated content for multi-channel approval routing via Slack or Email"
      },
      "typeVersion": 2.5
    },
    {
      "id": "b2a3aa4d-ad53-4fa2-aeeb-758524f32675",
      "name": "AI Agent1",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        -1248,
        1296
      ],
      "parameters": {
        "text": "=Enhance the following content for publishing. Make it more engaging and professional while keeping the original message intact. Return only the enhanced content, nothing else. Keep it short please.\n\nContent: {{ $json['Content Body'] }}",
        "options": {},
        "promptType": "define"
      },
      "typeVersion": 3.1
    },
    {
      "id": "316833b7-3a56-4c0c-8f18-b3fc9e5433f2",
      "name": "OpenAI Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        -1184,
        1520
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4o",
          "cachedResultName": "gpt-4o"
        },
        "options": {},
        "builtInTools": {}
      },
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "9988eb6a-b3bc-4caf-9583-9d95d82982e9",
      "name": "Route by Channel",
      "type": "n8n-nodes-base.switch",
      "position": [
        -896,
        1296
      ],
      "parameters": {
        "rules": {
          "values": [
            {
              "outputKey": "Slack",
              "conditions": {
                "options": {
                  "version": 3,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "fd55a0f7-397f-480b-97f2-b4311713d7bf",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $('On form submission1').item.json['Approval Channel'] }}",
                    "rightValue": "slack"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "Email",
              "conditions": {
                "options": {
                  "version": 3,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "e0cf2764-9264-4f84-b789-7e6491f2b7bf",
                    "operator": {
                      "name": "filter.operator.equals",
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $('On form submission1').item.json['Approval Channel'] }}",
                    "rightValue": "email"
                  }
                ]
              },
              "renameOutput": true
            }
          ]
        },
        "options": {}
      },
      "typeVersion": 3.4
    },
    {
      "id": "cad71c5b-918c-40a1-ada5-4baf93396386",
      "name": "Slack Approval Request",
      "type": "n8n-nodes-base.slack",
      "position": [
        -672,
        1104
      ],
      "parameters": {
        "user": {
          "__rl": true,
          "mode": "list",
          "value": "U0AB7QP5H1B",
          "cachedResultName": "elvissaravia"
        },
        "message": "=*Content Approval Required*\n\n*Original:*\n{{ $('On form submission1').item.json['Content Body'].substring(0,300) }}\n\n*AI Enhanced:*\n{{ $json.output.substring(0,300) }}",
        "options": {
          "limitWaitTime": {
            "values": {
              "resumeUnit": "minutes",
              "resumeAmount": 2
            }
          }
        },
        "operation": "sendAndWait",
        "authentication": "oAuth2",
        "approvalOptions": {
          "values": {
            "approvalType": "double",
            "disapproveLabel": "Reject"
          }
        }
      },
      "credentials": {
        "slackOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "5efdfe87-6d20-4fef-ba90-0c224e15b815",
      "name": "Slack Decision",
      "type": "n8n-nodes-base.switch",
      "position": [
        -448,
        1088
      ],
      "parameters": {
        "rules": {
          "values": [
            {
              "outputKey": "Timed Out",
              "conditions": {
                "options": {
                  "version": 3,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "loose"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "77d67b45-6916-4cab-986b-cecc0ece5bfd",
                    "operator": {
                      "type": "string",
                      "operation": "empty",
                      "singleValue": true
                    },
                    "leftValue": "={{ $json.data }}",
                    "rightValue": ""
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "Approved",
              "conditions": {
                "options": {
                  "version": 3,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "loose"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "557bf7ff-70e9-4732-8620-a7b0e22be3a5",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.data.approved }}",
                    "rightValue": "true"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "Rejected",
              "conditions": {
                "options": {
                  "version": 3,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "loose"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "6621782e-1c23-4e2e-b125-e962e30fd0b8",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.data.approved }}",
                    "rightValue": "false"
                  }
                ]
              },
              "renameOutput": true
            }
          ]
        },
        "options": {},
        "looseTypeValidation": true
      },
      "typeVersion": 3.4
    },
    {
      "id": "b9f8c952-c7cc-405d-85f1-84e8d7eba3a9",
      "name": "Publish Content",
      "type": "n8n-nodes-base.code",
      "position": [
        -224,
        1104
      ],
      "parameters": {
        "jsCode": "// Content approved - publish\nconst items = $input.all();\nreturn items.map(item => ({\n  json: {\n    status: 'published',\n    content: item.json.ai_enhanced_content || 'Approved content',\n    published_at: new Date().toISOString()\n  }\n}));"
      },
      "typeVersion": 2
    },
    {
      "id": "8ac35e39-93c6-49bb-b569-a43b49d4064a",
      "name": "Handle Rejection",
      "type": "n8n-nodes-base.code",
      "position": [
        -224,
        1296
      ],
      "parameters": {
        "jsCode": "// Content rejected - route back for revision\nconst items = $input.all();\nreturn items.map(item => ({\n  json: {\n    status: 'rejected',\n    content: item.json.original_content || 'Rejected',\n    rejected_at: new Date().toISOString(),\n    action: 'Send back to content team for revision'\n  }\n}));"
      },
      "typeVersion": 2
    },
    {
      "id": "b4914384-c828-470c-bcc5-66890d5c581f",
      "name": "Escalate to Manager",
      "type": "n8n-nodes-base.gmail",
      "position": [
        -224,
        1488
      ],
      "parameters": {
        "sendTo": "ellfae@gmail.com",
        "message": "=A content approval request received no response within 24 hours.\n\nOriginal content submitted:\n{{ $('On form submission1').item.json['Content Body'].substring(0,500) }}\n\nThe request was sent via {{ $('On form submission1').item.json['Approval Channel'] }} and no decision was made within the allowed timeframe.\n\nPlease review and take action.",
        "options": {},
        "subject": "=ESCALATION: Content Approval Timed Out",
        "emailType": "text"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "81b339e6-6344-42ea-bb30-40bfa69bbe09",
      "name": "Email Decision",
      "type": "n8n-nodes-base.switch",
      "position": [
        -448,
        1472
      ],
      "parameters": {
        "rules": {
          "values": [
            {
              "outputKey": "Timed Out",
              "conditions": {
                "options": {
                  "version": 3,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "loose"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "06bbf56d-4498-4412-917d-688511b8de9f",
                    "operator": {
                      "type": "string",
                      "operation": "empty",
                      "singleValue": true
                    },
                    "leftValue": "={{ $json.data }}",
                    "rightValue": ""
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "Approved",
              "conditions": {
                "options": {
                  "version": 3,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "loose"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "ae650af8-9e9e-41ca-a31d-65dfcc1ca3be",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.data.approved }}",
                    "rightValue": "true"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "Rejected",
              "conditions": {
                "options": {
                  "version": 3,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "loose"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "8a5edea2-7dfc-43f9-99ab-827da9d9f2b6",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.data.approved }}",
                    "rightValue": "false"
                  }
                ]
              },
              "renameOutput": true
            }
          ]
        },
        "options": {},
        "looseTypeValidation": true
      },
      "typeVersion": 3.4
    },
    {
      "id": "23dbf2b0-b565-4b89-b628-ccb8d8bea5c7",
      "name": "Email Approval Request",
      "type": "n8n-nodes-base.gmail",
      "position": [
        -672,
        1488
      ],
      "parameters": {
        "sendTo": "ellfae@gmail.com",
        "message": "=Content Approval Required\n\nOriginal:\n{{ $('On form submission1').item.json['Content Body'] }}\n\nAI Enhanced:\n{{ $json.output }}\n\nPlease review the content above and approve or reject.",
        "options": {
          "limitWaitTime": {
            "values": {
              "resumeUnit": "minutes"
            }
          }
        },
        "subject": "=Content Approval Required",
        "operation": "sendAndWait",
        "approvalOptions": {
          "values": {
            "approvalType": "double",
            "disapproveLabel": "Reject"
          }
        }
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "090c7433-0d2b-4703-88b0-814eb18347e1",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2368,
        1040
      ],
      "parameters": {
        "width": 752,
        "height": 656,
        "content": "## Multi-Channel Content Approval with Slack and Email Escalation\n\n### How it works\n1. **Form Trigger** collects a content draft and preferred review channel (Slack or Email).\n2. **AI Agent** enhances the submitted content using the connected LLM.\n3. **Route by Channel** (Switch node) directs the approval request to Slack or Email based on the form selection.\n4. **Approval nodes** send the content with Approve/Reject buttons and pause until the reviewer responds or the timeout expires.\n5. **Decision nodes** handle three outcomes: approved routes to publish, rejected routes to handling, timed out escalates to a manager via email.\n\n### Setup\n- Connect your **LLM credentials** (e.g., OpenAI) to the Chat Model node\n- Connect your **Slack credentials** and set the target channel on the Slack Approval Request node\n- Connect your **Gmail credentials** on the Email Approval Request and Escalate to Manager nodes\n- Set timeout durations on each approval node (e.g., 2-4 hours for operational reviews)\n\n### Customization\n- Add more review channels (e.g., Microsoft Teams) by extending the Switch node\n- Replace the Publish Content and Handle Rejection code nodes with your actual publishing logic\n\n\nThis template is a learning companion to the Production AI Playbook, a series that explores strategies, shares best practices, and provides practical examples for building reliable AI systems in n8n.  \n\n[Link to blog](https://go.n8n.io/PAP-HO-Blog)\n"
      },
      "typeVersion": 1
    },
    {
      "id": "e629a92b-3259-49f6-8283-5527a834272a",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1536,
        1024
      ],
      "parameters": {
        "color": 7,
        "width": 544,
        "height": 704,
        "content": "## Submit & Enhance\n"
      },
      "typeVersion": 1
    },
    {
      "id": "d4404a82-64ea-42d0-900b-64ccf968754b",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -960,
        1024
      ],
      "parameters": {
        "color": 7,
        "width": 448,
        "height": 704,
        "content": "## Route & Review"
      },
      "typeVersion": 1
    },
    {
      "id": "bee79d99-d6b7-45ab-98eb-b41d739a837e",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -480,
        1024
      ],
      "parameters": {
        "color": 7,
        "width": 448,
        "height": 704,
        "content": "## Decide & Act"
      },
      "typeVersion": 1
    }
  ],
  "connections": {
    "AI Agent1": {
      "main": [
        [
          {
            "node": "Route by Channel",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Email Decision": {
      "main": [
        [
          {
            "node": "Escalate to Manager",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Publish Content",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Handle Rejection",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Slack Decision": {
      "main": [
        [
          {
            "node": "Escalate to Manager",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Publish Content",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Handle Rejection",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Route by Channel": {
      "main": [
        [
          {
            "node": "Slack Approval Request",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Email Approval Request",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "AI Agent1",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "On form submission1": {
      "main": [
        [
          {
            "node": "AI Agent1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Email Approval Request": {
      "main": [
        [
          {
            "node": "Email Decision",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Slack Approval Request": {
      "main": [
        [
          {
            "node": "Slack Decision",
            "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.

Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

Route AI-generated content to reviewers on Slack or email, with automatic escalation if nobody responds. This template demonstrates a full multi-channel review workflow with timeout handling.

Source: https://n8n.io/workflows/13849/ — original creator credit. Request a take-down →

More AI & RAG workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

AI & RAG

This workflow automates legal policy governance for legal teams, policy managers, and compliance officers, eliminating manual document review, approval classification, and multi-channel stakeholder di

Form Trigger, OpenAI Chat, Agent Tool +7
AI & RAG

This workflow contains community nodes that are only compatible with the self-hosted version of n8n.

Google Sheets, Form Trigger, Output Parser Structured +7
AI & RAG

Whether you’re a product manager, developer, or simply curious about workflow automation, you’re in the right place. This n8n workflow is designed to help you streamline and automate your social media

Output Parser Structured, OpenAI Chat, LinkedIn +8
AI & RAG

This workflow turns your website form into a fully automated AI Lead Qualification system. Whenever a new lead submits your form, the workflow: Receives the submission through a Webhook Cleans and nor

Form Trigger, Agent, OpenAI Chat +7
AI & RAG

Onboarding Workflow. Uses gmail, formTrigger, stickyNote, slack. Event-driven trigger; 19 nodes.

Gmail, Form Trigger, Slack +5