AutomationFlowsMarketing & Ads › Route and Validate B2b Form Leads with Webhook Firewall and SMTP Emails

Route and Validate B2b Form Leads with Webhook Firewall and SMTP Emails

ByMychel Garzon @mychel-garzon on n8n.io

For specialized B2B agencies, consultancies, and MSPs, lead routing isn't about guessing "purchasing temperature" it’s about distinct operational tracks. An "Infrastructure Audit" requires vastly different triage than a "Managed Services" request. This workflow acts as a…

Webhook trigger★★★★☆ complexity16 nodesEmail Send
Marketing & Ads Trigger: Webhook Nodes: 16 Complexity: ★★★★☆ Added:

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

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
{
  "id": "TD0LsjPaGHjbO3LM",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Precision Form Router & Validater",
  "tags": [],
  "nodes": [
    {
      "id": "16dfd0c1-39c8-48d7-94c4-a9c492679a44",
      "name": "README",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        256,
        4944
      ],
      "parameters": {
        "width": 640,
        "height": 420,
        "content": "# Precision Form Router & Validater \n\n## How it works\n1. **Trigger**: Captures inbound form submissions via Tally webhook.\n2. **Format**: Extracts complex nested arrays into clean key-value pairs.\n3. **Validate**: Acts as a firewall, using Regex to drop malformed email addresses.\n4. **Route**: Evaluates the requested service tier and deterministically routes the prospect.\n5. **Execute**: Sends parallel internal alerts and tailored customer emails (with a catch-all fallback).\n\n## Setup steps\n- [ ] Connect your SMTP/Email Credentials in n8n\n- [ ] Update `hello@yourdomain.com` and `admin@yourdomain.com` placeholders\n- [ ] Customize the HTML email templates for your specific offerings\n- [ ] Copy the Webhook URL and paste it into your Tally form settings"
      },
      "typeVersion": 1
    },
    {
      "id": "b9beec46-4e3d-4427-b931-256c5da36578",
      "name": "Sticky Note - Section 1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        992,
        5024
      ],
      "parameters": {
        "color": 7,
        "width": 840,
        "height": 260,
        "content": "###  Ingestion & Validation\nListens for the Tally webhook. The custom JS Code node extracts deeply nested multi-choice values. The IF node acts as a Regex firewall to validate email syntax."
      },
      "typeVersion": 1
    },
    {
      "id": "eda0f04b-10b6-4d8e-92c9-9f008ed176a6",
      "name": "Sticky Note - Section 2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1984,
        4304
      ],
      "parameters": {
        "color": 7,
        "width": 726,
        "height": 852,
        "content": "### Deterministic Routing & External Comms\nEvaluates the selected tier and routes to the matching email branch. Unmapped tiers are safely routed to the Fallback branch. Nodes continue on fail."
      },
      "typeVersion": 1
    },
    {
      "id": "5a86a183-8d99-4fed-92c9-1f556956e50c",
      "name": "Sticky Note - Section 3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1984,
        5184
      ],
      "parameters": {
        "color": 7,
        "width": 726,
        "height": 414,
        "content": "### Internal Comms & Webhook Closure\nFires an internal lead notification in parallel. Finally, responds to the originating webhook with a 200 Success or a JSON Error payload."
      },
      "typeVersion": 1
    },
    {
      "id": "625c6177-bc0d-411f-8fb8-5695d76003d3",
      "name": "Form Webhook",
      "type": "n8n-nodes-base.webhook",
      "position": [
        1040,
        5136
      ],
      "parameters": {
        "path": "your-form-path",
        "options": {},
        "httpMethod": "POST",
        "responseMode": "responseNode"
      },
      "typeVersion": 2
    },
    {
      "id": "77614242-1cec-491e-96c9-17925d845c55",
      "name": "Format Tally Data",
      "type": "n8n-nodes-base.code",
      "position": [
        1264,
        5136
      ],
      "parameters": {
        "jsCode": "// Get all fields from the webhook\nconst fields = $input.item.json.body.data.fields || [];\n\nfunction getReadableValue(field) {\n  if (field.type === 'MULTIPLE_CHOICE' && field.options && field.value) {\n    const selectedId = field.value[0];\n    const matchingOption = field.options.find(opt => opt.id === selectedId);\n    return matchingOption ? matchingOption.text : field.value[0];\n  }\n  return field.value;\n}\n\nconst mappedData = {\n  name: '',\n  email: '',\n  company: '',\n  tier: '',\n  allFieldsText: '',\n  challenge: 'Not provided'\n};\n\nfields.forEach(field => {\n  const label = field.label ? field.label.toLowerCase() : '';\n  \n  if (label.includes('name') && !label.includes('company')) {\n    mappedData.name = field.value;\n  }\n  if (field.type === 'INPUT_EMAIL') {\n    mappedData.email = field.value;\n  }\n  if (label.includes('company')) {\n    mappedData.company = field.value;\n  }\n  if (field.label === 'tier') {\n    mappedData.tier = field.value;\n  }\n  if (field.type === 'TEXTAREA' && field.value) {\n    mappedData.challenge = field.value;\n  }\n});\n\nconst allFieldsArray = [];\nfields.forEach(field => {\n  if (field.type !== 'HIDDEN_FIELDS' && field.value !== null) {\n    const readableValue = getReadableValue(field);\n    allFieldsArray.push(`${field.label}: ${readableValue}`);\n  }\n});\n\nmappedData.allFieldsText = allFieldsArray.join('\\n');\n\nreturn {\n  json: mappedData\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "8702b28f-ff80-4fe4-a2eb-c354fdc56d01",
      "name": "Extract Form Data",
      "type": "n8n-nodes-base.set",
      "position": [
        1488,
        5136
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "name",
              "name": "name",
              "type": "string",
              "value": "={{ $json.name }}"
            },
            {
              "id": "email",
              "name": "email",
              "type": "string",
              "value": "={{ $json.email }}"
            },
            {
              "id": "company",
              "name": "company",
              "type": "string",
              "value": "={{ $json.company }}"
            },
            {
              "id": "tier",
              "name": "tier",
              "type": "string",
              "value": "={{ $json.tier }}"
            },
            {
              "id": "allFields",
              "name": "allFields",
              "type": "string",
              "value": "={{ $json.allFieldsText }}"
            },
            {
              "id": "challenge",
              "name": "challenge",
              "type": "string",
              "value": "={{ $json.challenge }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "013fd4e8-70b5-4c7f-87b9-dd02cd0b3a72",
      "name": "Validate Lead",
      "type": "n8n-nodes-base.if",
      "position": [
        1712,
        5136
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": false,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "val1",
              "operator": {
                "type": "string",
                "operation": "notEmpty",
                "singleValue": true
              },
              "leftValue": "={{ $json.email }}",
              "rightValue": ""
            },
            {
              "id": "val2",
              "operator": {
                "type": "string",
                "operation": "regex"
              },
              "leftValue": "={{ $json.email }}",
              "rightValue": "^[^@\\s]+@[^@\\s]+\\.[^@\\s]+$"
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "328ce3cd-0300-417e-8118-969191a60c81",
      "name": "Switch by Service Tier",
      "type": "n8n-nodes-base.switch",
      "position": [
        2080,
        4656
      ],
      "parameters": {
        "rules": {
          "values": [
            {
              "conditions": {
                "options": {
                  "version": 1,
                  "leftValue": "",
                  "caseSensitive": false,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "r1",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.tier }}",
                    "rightValue": "Audit"
                  }
                ]
              }
            },
            {
              "conditions": {
                "options": {
                  "version": 1,
                  "leftValue": "",
                  "caseSensitive": false,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "r2",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.tier }}",
                    "rightValue": "Implementation"
                  }
                ]
              }
            },
            {
              "conditions": {
                "options": {
                  "version": 1,
                  "leftValue": "",
                  "caseSensitive": false,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "r3",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.tier }}",
                    "rightValue": "Managed Services"
                  }
                ]
              }
            },
            {
              "conditions": {
                "options": {
                  "version": 1,
                  "leftValue": "",
                  "caseSensitive": false,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "r4",
                    "operator": {
                      "type": "string",
                      "operation": "regex"
                    },
                    "leftValue": "={{ $json.tier }}",
                    "rightValue": ".*"
                  }
                ]
              }
            }
          ]
        },
        "options": {}
      },
      "typeVersion": 3.1
    },
    {
      "id": "fc4b7df8-dc4a-45ec-b342-2730c932f056",
      "name": "Email - Audit",
      "type": "n8n-nodes-base.emailSend",
      "onError": "continueErrorOutput",
      "position": [
        2304,
        4400
      ],
      "parameters": {
        "html": "=<!DOCTYPE html>\n<html>\n<body>\n  <div class=\"container\">\n    <h2>Hi {{ $json.name.split(' ')[0] }},</h2>\n    <p>Thanks for your inquiry about an <strong>Audit</strong>.</p>\n    <p>We've received your message and will get back to you shortly.</p>\n    <p>Best regards,<br><strong>Your Team</strong></p>\n  </div>\n</body>\n</html>",
        "options": {},
        "subject": "Thanks for your inquiry - {{ $json.company }}",
        "toEmail": "={{ $json.email }}",
        "fromEmail": "user@example.com"
      },
      "typeVersion": 2.1
    },
    {
      "id": "479d271b-ec6c-4377-8bb5-8c469c4c1952",
      "name": "Email - Implementation",
      "type": "n8n-nodes-base.emailSend",
      "onError": "continueErrorOutput",
      "position": [
        2304,
        4592
      ],
      "parameters": {
        "html": "=<!DOCTYPE html>\n<html>\n<body>\n  <div class=\"container\">\n    <h2>Hi {{ $json.name.split(' ')[0] }},</h2>\n    <p>Thanks for your interest in our <strong>Implementation</strong> services.</p>\n    <p>We've received your message and will get back to you shortly.</p>\n    <p>Best regards,<br><strong>Your Team</strong></p>\n  </div>\n</body>\n</html>",
        "options": {},
        "subject": "Thanks for your inquiry - {{ $json.company }}",
        "toEmail": "={{ $json.email }}",
        "fromEmail": "user@example.com"
      },
      "typeVersion": 2.1
    },
    {
      "id": "b80a9d76-2beb-440f-8953-9e50c47128f4",
      "name": "Email - Managed Services",
      "type": "n8n-nodes-base.emailSend",
      "onError": "continueErrorOutput",
      "position": [
        2304,
        4784
      ],
      "parameters": {
        "html": "=<!DOCTYPE html>\n<html>\n<body>\n  <div class=\"container\">\n    <h2>Hi {{ $json.name.split(' ')[0] }},</h2>\n    <p>Thanks for your interest in our <strong>Managed Services</strong>.</p>\n    <p>We've received your message and will get back to you shortly.</p>\n    <p>Best regards,<br><strong>Your Team</strong></p>\n  </div>\n</body>\n</html>",
        "options": {},
        "subject": "Thanks for your inquiry - {{ $json.company }}",
        "toEmail": "={{ $json.email }}",
        "fromEmail": "user@example.com"
      },
      "typeVersion": 2.1
    },
    {
      "id": "ee514e74-9211-4f71-9e05-2fd2847e5236",
      "name": "Email - Generic/Fallback",
      "type": "n8n-nodes-base.emailSend",
      "onError": "continueErrorOutput",
      "position": [
        2304,
        4976
      ],
      "parameters": {
        "html": "=<!DOCTYPE html>\n<html>\n<body>\n  <div class=\"container\">\n    <h2>Hi {{ $json.name.split(' ')[0] }},</h2>\n    <p>Thanks for your inquiry.</p>\n    <p>We've received your message and will get back to you shortly.</p>\n    <p>Best regards,<br><strong>Your Team</strong></p>\n  </div>\n</body>\n</html>",
        "options": {},
        "subject": "Thanks for your inquiry - {{ $json.company }}",
        "toEmail": "={{ $json.email }}",
        "fromEmail": "user@example.com"
      },
      "typeVersion": 2.1
    },
    {
      "id": "f090f7ab-8406-4fc1-a483-2aa6a94da2d0",
      "name": "Notify Internal Team",
      "type": "n8n-nodes-base.emailSend",
      "onError": "continueErrorOutput",
      "position": [
        2208,
        5296
      ],
      "parameters": {
        "html": "=<h2>\ud83c\udfaf New Lead Notification</h2>\n<p><strong>Name:</strong> {{ $json.name }}</p>\n<p><strong>Email:</strong> {{ $json.email }}</p>\n<p><strong>Company:</strong> {{ $json.company }}</p>\n<p><strong>Tier:</strong> {{ $json.tier }}</p>\n<p><strong>Challenge:</strong> {{ $json.challenge }}</p>",
        "options": {},
        "subject": "=\ud83c\udfaf New {{ $json.tier.toUpperCase() }} Lead - {{ $json.company }}",
        "toEmail": "user@example.com",
        "fromEmail": "user@example.com"
      },
      "typeVersion": 2.1
    },
    {
      "id": "85112e07-e297-40a0-a47e-990dd4fd954b",
      "name": "Success Response",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        2464,
        5280
      ],
      "parameters": {
        "options": {},
        "respondWith": "json",
        "responseBody": "={{ { \"success\": true } }}"
      },
      "typeVersion": 1.1
    },
    {
      "id": "e02171b5-c3ad-4655-83ec-8aef33987166",
      "name": "Error Response",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        2208,
        5456
      ],
      "parameters": {
        "options": {},
        "respondWith": "json",
        "responseBody": "={{ { \"success\": false, \"error\": \"Invalid email format provided\" } }}"
      },
      "typeVersion": 1.1
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "executionOrder": "v1"
  },
  "versionId": "67739cf2-57ae-4a0c-901b-e5fe0c7dc8e5",
  "connections": {
    "Form Webhook": {
      "main": [
        [
          {
            "node": "Format Tally Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Validate Lead": {
      "main": [
        [
          {
            "node": "Switch by Service Tier",
            "type": "main",
            "index": 0
          },
          {
            "node": "Notify Internal Team",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Error Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Form Data": {
      "main": [
        [
          {
            "node": "Validate Lead",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format Tally Data": {
      "main": [
        [
          {
            "node": "Extract Form Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Notify Internal Team": {
      "main": [
        [
          {
            "node": "Success Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Switch by Service Tier": {
      "main": [
        [
          {
            "node": "Email - Audit",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Email - Implementation",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Email - Managed Services",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Email - Generic/Fallback",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
Pro

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

About this workflow

For specialized B2B agencies, consultancies, and MSPs, lead routing isn't about guessing "purchasing temperature" it’s about distinct operational tracks. An "Infrastructure Audit" requires vastly different triage than a "Managed Services" request. This workflow acts as a…

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

More Marketing & Ads workflows → · Browse all categories →

Related workflows

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

Marketing & Ads

Ad agencies needing automated lead capture. Sales teams fighting fraud and scoring leads. B2B SaaS companies nurturing prospects. Marketing pros boosting sales pipelines. Captures leads via Webhook fr

HTTP Request, Google Sheets, Slack +2
Marketing & Ads

Store leads in a SQL Server database via REST API with automatic scoring and Slack notifications.

HTTP Request, Slack, Error Trigger
Marketing & Ads

This n8n workflow automatically captures LinkedIn leads from multiple sources (new connections, post engagements), enriches the data with AI-powered scoring, eliminates duplicates, syncs to Google She

LinkedIn, Google Sheets, HTTP Request +1
Marketing & Ads

Create records in Odoo from any webform via a secure webhook. The workflow validates required fields, resolves UTMs by name (source, medium, campaign) and writes standard lead fields in Odoo. Clean, p

Odoo, Execution Data
Marketing & Ads

This workflow captures raw lead data from a Webhook and formats it into a clean, structured object — perfectly tailored for Odoo CRM and create lead. It supports Odoo versions 15, 16, 17, and 18, both

Odoo