← All Productivity Workflows
BillionVerifySlack

Form to meeting: Google Calendar, Zoom, Gmail & Slack booking automation

Pull contacts, verify each address with BillionVerify, and continue to Slack — only deliverable addresses get through.

Why verify before the send

Sending to invalid, risky, catch-all, or disposable addresses spikes your bounce rate and erodes sender reputation. A verification gate before the Slack step removes that risk automatically — only deliverable addresses continue, the rest are flagged.

The workflow

BillionVerify — verification sits right before the send.

Node by node

  1. 1
    Google Forms Webhook1Source· n8n

    Provides or transforms the contact data flowing through the workflow.

  2. 2
    Merge Form Data1Source· n8n

    Provides or transforms the contact data flowing through the workflow.

  3. 3
    Workflow Configuration1Source· n8n

    Provides or transforms the contact data flowing through the workflow.

  4. 4
    Extract Booking Details1Source· n8n

    Provides or transforms the contact data flowing through the workflow.

  5. 5
    Check Calendar Availability1Source· n8n

    Provides or transforms the contact data flowing through the workflow.

  6. 6
    Is Time Slot Available?1Logic· n8n

    Branches on the verification result: only deliverable addresses continue to the send; the rest are skipped and flagged.

  7. 7
    Create Calendar Event1Source· n8n

    Provides or transforms the contact data flowing through the workflow.

  8. 8
    Verify Email (BillionVerify) 2Verify· billionverify

    The BillionVerify node verifies the address — status (valid / invalid / risky / catch-all / role / disposable), is_deliverable, and a confidence score — before anything is sent.

  9. 9
    Create Zoom Meeting1Source· n8n

    Provides or transforms the contact data flowing through the workflow.

  10. 10
    IF deliverable 2Logic· n8n

    Branches on the verification result: only deliverable addresses continue to the send; the rest are skipped and flagged.

  11. 11
    Verify Email (BillionVerify)Verify· billionverify

    The BillionVerify node verifies the address — status (valid / invalid / risky / catch-all / role / disposable), is_deliverable, and a confidence score — before anything is sent.

  12. 12
    Send Unavailable Email1Send· n8n

    Sends only to verified, deliverable addresses. Swap in your own provider node if you send elsewhere.

  13. 13
    IF deliverableLogic· n8n

    Branches on the verification result: only deliverable addresses continue to the send; the rest are skipped and flagged.

  14. 14
    Send Confirmation Email1Send· n8n

    Sends only to verified, deliverable addresses. Swap in your own provider node if you send elsewhere.

  15. 15
    Notify Teammate on Slack1Source· n8n

    Provides or transforms the contact data flowing through the workflow.

Workflow JSON

Copy or download this workflow, then import it in n8n (Workflows → Import from File / Paste). Install the BillionVerify community node first, then add your API key credential.

verify-emails-in-slack.json
{
  "name": "Form to meeting: Google Calendar, Zoom, Gmail & Slack booking automation + BillionVerify",
  "nodes": [
    {
      "id": "3dd27b86-6e03-4595-a9fa-2fe3d1210611",
      "name": "Google Forms Webhook1",
      "type": "n8n-nodes-base.webhook",
      "position": [
        176,
        208
      ],
      "webhookId": "0c79affb-61ad-4802-8580-66c5856d66cf",
      "parameters": {
        "path": "google-forms-booking",
        "options": {},
        "httpMethod": "POST",
        "responseMode": "lastNode"
      },
      "typeVersion": 2.1
    },
    {
      "id": "957b6711-281f-4599-9962-84ebf221691a",
      "name": "Merge Form Data1",
      "type": "n8n-nodes-base.merge",
      "position": [
        496,
        224
      ],
      "parameters": {},
      "typeVersion": 3.2
    },
    {
      "id": "3b63fe73-a5e7-4f3e-bf61-e7bd0a9aa63c",
      "name": "Workflow Configuration1",
      "type": "n8n-nodes-base.set",
      "position": [
        848,
        224
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "id-1",
              "name": "calendarId",
              "type": "string",
              "value": "user@example.com"
            },
            {
              "id": "id-2",
              "name": "slackChannel",
              "type": "string",
              "value": "C09GN4NCTAP"
            },
            {
              "id": "id-3",
              "name": "teammateEmail",
              "type": "string",
              "value": "user@example.com"
            }
          ]
        },
        "includeOtherFields": true
      },
      "typeVersion": 3.4
    },
    {
      "id": "66b2895b-8260-4e40-b4ec-39b100b89f77",
      "name": "Extract Booking Details1",
      "type": "n8n-nodes-base.set",
      "position": [
        1168,
        224
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "id-1",
              "name": "customerName",
              "type": "string",
              "value": "={{ $json.body.name }}"
            },
            {
              "id": "id-2",
              "name": "customerEmail",
              "type": "string",
              "value": "={{ $json.body.email }}"
            },
            {
              "id": "id-3",
              "name": "bookingDate",
              "type": "string",
              "value": "={{ $json.body.date }}"
            },
            {
              "id": "id-4",
              "name": "bookingTime",
              "type": "string",
              "value": "={{ $json.body.time }}"
            },
            {
              "id": "34865dea-9db2-4f35-b91b-322572680869",
              "name": "bookingStartISO",
              "type": "string",
              "value": "={{ new Date($json.body.date + 'T' + $json.body.time + ':00+09:00').toISOString() }}"
            },
            {
              "id": "941d5f18-54fd-41ad-8f46-c9f9f13fb32f",
              "name": "bookingEndISO",
              "type": "string",
              "value": "={{ new Date(new Date($json.body.date + 'T' + $json.body.time + ':00+09:00').getTime() + 60*60*1000).toISOString() }}"
            }
          ]
        },
        "includeOtherFields": true
      },
      "typeVersion": 3.4
    },
    {
      "id": "6591a8f7-2400-4de8-9fbe-b35271faf1f8",
      "name": "Check Calendar Availability1",
      "type": "n8n-nodes-base.googleCalendar",
      "position": [
        1472,
        224
      ],
      "parameters": {
        "options": {},
        "timeMax": "={{ $json.bookingEndISO }}",
        "timeMin": "={{ $json.bookingStartISO }}",
        "calendar": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Workflow Configuration1').first().json.calendarId }}"
        },
        "operation": "getAll"
      },
      "typeVersion": 1.3,
      "alwaysOutputData": true
    },
    {
      "id": "d80641b0-9da6-491c-922f-d278c0f030c3",
      "name": "Is Time Slot Available?1",
      "type": "n8n-nodes-base.if",
      "position": [
        1824,
        224
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "14e9293a-f96c-45f1-b216-2c8aaf2fb3e2",
              "operator": {
                "type": "object",
                "operation": "empty",
                "singleValue": true
              },
              "leftValue": "={{ $json }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "76a27cb5-7196-4564-a89a-85d5d0a41d52",
      "name": "Create Calendar Event1",
      "type": "n8n-nodes-base.googleCalendar",
      "position": [
        2144,
        208
      ],
      "parameters": {
        "end": "={{ $('Extract Booking Details1').first().json.bookingEndISO }}",
        "start": "={{ $('Extract Booking Details1').first().json.bookingStartISO }}",
        "calendar": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Workflow Configuration1').first().json.calendarId }}"
        },
        "additionalFields": {
          "summary": "=Booking with {{ $('Extract Booking Details1').first().json.customerName }}",
          "attendees": [
            "={{ $('Extract Booking Details1').first().json.customerEmail }}"
          ],
          "description": "=Customer: {{ $('Extract Booking Details1').first().json.customerName }} ({{ $('Extract Booking Details1').first().json.customerEmail }})"
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "9f4ca36f-8f02-43ee-8630-222958201959",
      "name": "Create Zoom Meeting1",
      "type": "n8n-nodes-base.zoom",
      "position": [
        2416,
        208
      ],
      "parameters": {
        "topic": "=Booking with {{ $('Extract Booking Details1').first().json.customerName }}",
        "authentication": "oAuth2",
        "additionalFields": {
          "duration": 60,
          "timeZone": "UTC",
          "startTime": "={{ $('Extract Booking Details1').first().json.bookingStartISO }}"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "a31d67fa-38b4-4276-a0ad-56d1069f95dd",
      "name": "Send Confirmation Email1",
      "type": "n8n-nodes-base.gmail",
      "position": [
        2720,
        208
      ],
      "webhookId": "f28b9459-360b-4cad-9f2e-0d69654e795b",
      "parameters": {
        "sendTo": "={{ $('Extract Booking Details1').first().json.customerEmail }}",
        "message": "=Hi {{ $('Extract Booking Details1').first().json.customerName }},\n\nYour booking has been confirmed!\n\nDate & Time: {{ new Date($('Extract Booking Details1').first().json.bookingStartISO).toLocaleString('ja-JP', { timeZone: 'Asia/Tokyo' }) }}\n\nZoom Meeting Link: {{ $json.join_url }}\n\nLooking forward to meeting you!\n\nBest regards",
        "options": {},
        "subject": "=Booking Confirmed: {{ new Date($('Extract Booking Details1').first().json.bookingStartISO).toLocaleString('ja-JP', { timeZone: 'Asia/Tokyo' }) }}"
      },
      "typeVersion": 2.1
    },
    {
      "id": "b456c4f9-dcca-48a4-b750-f39e95df493f",
      "name": "Notify Teammate on Slack1",
      "type": "n8n-nodes-base.slack",
      "position": [
        3040,
        208
      ],
      "webhookId": "866a3241-98d2-4db1-b791-c8c8f83b99b9",
      "parameters": {
        "text": "=🎉 New booking confirmed!\n\n*Customer:* {{ $('Extract Booking Details1').first().json.customerName }} ({{ $('Extract Booking Details1').first().json.customerEmail }})\n*Date & Time:* {{ new Date($('Extract Booking Details1').first().json.bookingStartISO).toLocaleString('ja-JP', { timeZone: 'Asia/Tokyo' }) }}\n*Zoom Link:* {{ $json.join_url }}",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Workflow Configuration1').first().json.slackChannel }}"
        },
        "otherOptions": {},
        "authentication": "oAuth2"
      },
      "typeVersion": 2.3
    },
    {
      "id": "78d4ae92-b136-4bbe-ae52-a73a60c47a6c",
      "name": "Send Unavailable Email1",
      "type": "n8n-nodes-base.gmail",
      "position": [
        2144,
        512
      ],
      "webhookId": "98dd0319-284e-4b12-a655-a57577571800",
      "parameters": {
        "sendTo": "={{ $('Extract Booking Details1').first().json.customerEmail }}",
        "message": "=Hi {{ $('Extract Booking Details1').first().json.customerName }},\n\nThank you for your booking request. Unfortunately, the requested time slot on {{ new Date($('Extract Booking Details1').first().json.bookingStartISO).toLocaleString('ja-JP', { timeZone: 'Asia/Tokyo' }) }} is not available.\n\nPlease submit a new booking request with an alternative time.",
        "options": {},
        "subject": "Time Slot Unavailable"
      },
      "typeVersion": 2.1
    },
    {
      "id": "9f8af7ba-09f1-46bb-9bc6-bb2d0b26d744",
      "name": "Sticky: Google Forms Webhook1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        96,
        -400
      ],
      "parameters": {
        "color": "white",
        "width": 768,
        "height": 528,
        "content": "Title: Automated Booking → Calendar + Zoom + Email + Slack\nWhat this workflow does\n\nCaptures booking submissions from a form and parses date/time.\n\nChecks Google Calendar for conflicts.\n\nIf free: creates a Calendar event → creates a Zoom meeting → emails the guest → notifies your team on Slack.\n\nIf busy: emails the guest to pick another time.\n\nFlow\nWebhook → Merge → Config → Extract details → Check availability → IF (free/busy) →\n[Free] Create Calendar Event → Create Zoom → Email confirmation → Slack notify\n[Busy] Email unavailability\n\nNotes\n\nKeep all user-editable variables in the Set nodes for easy maintenance.\n\nDate handling assumes Asia/Tokyo input and converts to ISO for API calls.\n\nNo hardcoded credentials inside HTTP nodes; store secrets via Credentials."
      },
      "typeVersion": 1
    },
    {
      "id": "5eb1dc05-5c0f-44a0-9000-d4abdd74a981",
      "name": "Sticky: Merge Form Data1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        80,
        384
      ],
      "parameters": {
        "color": "white",
        "width": 256,
        "height": 176,
        "content": "Purpose: Entry point for bookings. Receives a POST payload from your form (name, email, date, time).\nOutput: Raw form fields under body.* used downstream."
      },
      "typeVersion": 1
    },
    {
      "id": "967bcc58-fc07-4e4c-8b17-5f2a99f9287f",
      "name": "Sticky: Workflow Configuration1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        400,
        384
      ],
      "parameters": {
        "color": "white",
        "width": 272,
        "height": 176,
        "content": "Purpose: Normalizes/forwards webhook data to keep a single item moving through the flow.\nTip: Use this as a “buffer” if you ever add parallel inputs later."
      },
      "typeVersion": 1
    },
    {
      "id": "663ecdf9-6f9d-481c-abe6-e7d8b3c34021",
      "name": "Sticky: Extract Booking Details1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        736,
        384
      ],
      "parameters": {
        "color": "white",
        "width": 288,
        "height": 176,
        "content": "Purpose: Central place for editable constants (e.g., calendarId, slackChannel, teammateEmail).\nWhy: Makes the template plug-and-play—update values here instead of hunting through nodes."
      },
      "typeVersion": 1
    },
    {
      "id": "c12bee38-9494-43b7-9961-2e4971a92316",
      "name": "Sticky: Check Calendar Availability1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1088,
        384
      ],
      "parameters": {
        "color": "white",
        "width": 272,
        "height": 176,
        "content": "Purpose: Maps form fields to clean variables: customerName, customerEmail, bookingDate, bookingTime.\nAlso: Builds bookingStartISO and bookingEndISO (60-min duration) using the submitted local time (JST) → ISO strings."
      },
      "typeVersion": 1
    },
    {
      "id": "b58f33ab-ad60-4a98-9354-3ed1a1aeab72",
      "name": "Sticky: Is Time Slot Available?1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1424,
        384
      ],
      "parameters": {
        "color": "white",
        "width": 256,
        "height": 176,
        "content": "Purpose: Queries the target calendar for events overlapping bookingStartISO–bookingEndISO.\nBehavior: Returns an empty list when the slot is free; non-empty when it’s taken."
      },
      "typeVersion": 1
    },
    {
      "id": "b0b7376c-f552-4ce9-bd31-33919ba04618",
      "name": "Sticky: Create Calendar Event1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1744,
        384
      ],
      "parameters": {
        "color": "white",
        "width": 256,
        "height": 176,
        "content": "Purpose: Branches on availability.\nTrue (empty result): Slot is free → proceed to create the event.\nFalse (has events): Slot is busy → send “unavailable” email."
      },
      "typeVersion": 1
    },
    {
      "id": "bb03b52c-ddc4-4896-9016-6d01ab6b68ec",
      "name": "Sticky: Create Zoom Meeting1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2000,
        16
      ],
      "parameters": {
        "color": "white",
        "width": 272,
        "content": "Purpose: Books the time on Google Calendar with the guest as an attendee.\nFields: Summary includes guest name; Description includes name + email for quick context."
      },
      "typeVersion": 1
    },
    {
      "id": "73736740-501f-4814-9722-e8576e2dd21f",
      "name": "Sticky: Send Confirmation Email1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2336,
        16
      ],
      "parameters": {
        "color": "white",
        "content": "Purpose: Creates a Zoom meeting for the confirmed slot.\nTiming: Uses the booking start time and a 60-minute duration.\nOutput: Provides join_url used by Email/Slack steps."
      },
      "typeVersion": 1
    },
    {
      "id": "6e9c22c3-0b31-47f9-ab96-4476e501175d",
      "name": "Sticky: Notify Teammate on Slack1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2640,
        16
      ],
      "parameters": {
        "color": "white",
        "width": 256,
        "content": "Purpose: Sends a confirmation to the guest with local (Japan) date/time and the Zoom link.\nSubject/Body: Human-readable datetime via toLocaleString('ja-JP', { timeZone: 'Asia/Tokyo' })."
      },
      "typeVersion": 1
    },
    {
      "id": "b9aa000c-63a2-44b1-800a-c041a1582f64",
      "name": "Sticky: Send Unavailable Email1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2064,
        672
      ],
      "parameters": {
        "color": "white",
        "width": 256,
        "content": "Purpose: Notifies the guest when the requested slot is already taken and asks them to rebook another time."
      },
      "typeVersion": 1
    },
    {
      "id": "3904238d-39eb-40f0-879f-3f17e1afd303",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2960,
        16
      ],
      "parameters": {
        "content": "Purpose: Posts a concise booking summary to your specified Slack channel.\nIncludes: Guest name/email, localized date/time, and Zoom join_url."
      },
      "typeVersion": 1
    },
    {
      "parameters": {
        "operation": "verify",
        "email": "={{ $('Extract Booking Details1').first().json.customerEmail }}",
        "additionalOptions": {}
      },
      "type": "n8n-nodes-billionverify.billionVerify",
      "typeVersion": 1,
      "position": [
        2360,
        208
      ],
      "name": "Verify Email (BillionVerify)",
      "credentials": {
        "billionVerifyApi": {
          "id": "",
          "name": "BillionVerify account"
        }
      }
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "loose"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "is-deliverable",
              "leftValue": "={{ $json.is_deliverable }}",
              "rightValue": "",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ]
        }
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        2540,
        208
      ],
      "name": "IF deliverable"
    },
    {
      "parameters": {
        "operation": "verify",
        "email": "={{ $('Extract Booking Details1').first().json.customerEmail }}",
        "additionalOptions": {}
      },
      "type": "n8n-nodes-billionverify.billionVerify",
      "typeVersion": 1,
      "position": [
        1784,
        512
      ],
      "name": "Verify Email (BillionVerify) 2",
      "credentials": {
        "billionVerifyApi": {
          "id": "",
          "name": "BillionVerify account"
        }
      }
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "loose"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "is-deliverable",
              "leftValue": "={{ $json.is_deliverable }}",
              "rightValue": "",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ]
        }
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        1964,
        512
      ],
      "name": "IF deliverable 2"
    }
  ],
  "connections": {
    "Merge Form Data1": {
      "main": [
        [
          {
            "node": "Workflow Configuration1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create Zoom Meeting1": {
      "main": [
        [
          {
            "node": "Verify Email (BillionVerify)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google Forms Webhook1": {
      "main": [
        [
          {
            "node": "Merge Form Data1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create Calendar Event1": {
      "main": [
        [
          {
            "node": "Create Zoom Meeting1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Workflow Configuration1": {
      "main": [
        [
          {
            "node": "Extract Booking Details1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Booking Details1": {
      "main": [
        [
          {
            "node": "Check Calendar Availability1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Is Time Slot Available?1": {
      "main": [
        [
          {
            "node": "Create Calendar Event1",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Verify Email (BillionVerify) 2",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Confirmation Email1": {
      "main": [
        [
          {
            "node": "Notify Teammate on Slack1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check Calendar Availability1": {
      "main": [
        [
          {
            "node": "Is Time Slot Available?1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Verify Email (BillionVerify)": {
      "main": [
        [
          {
            "node": "IF deliverable",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "IF deliverable": {
      "main": [
        [
          {
            "node": "Send Confirmation Email1",
            "type": "main",
            "index": 0
          }
        ],
        []
      ]
    },
    "Verify Email (BillionVerify) 2": {
      "main": [
        [
          {
            "node": "IF deliverable 2",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "IF deliverable 2": {
      "main": [
        [
          {
            "node": "Send Unavailable Email1",
            "type": "main",
            "index": 0
          }
        ],
        []
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  }
}

When to use this

  • Cleaning a list before a Slack send or sync.
  • Protecting Slack deliverability and sender reputation.
  • Keeping bounce rates low so your sending is never throttled.

FAQ

Why verify before sending in Slack?

Verifying first keeps your bounce rate low, which protects your sender reputation and your results.

How do I import this workflow?

Download the JSON, then in n8n go to Workflows → Import from File (or paste it). Install the BillionVerify community node and add your API key credential.

What happens to risky or catch-all addresses?

They are routed to the false branch and excluded from the send. You decide whether to retry, review, or drop them.

Add verification to your workflow

Create a free account, grab your API key, and stop bounces before they happen.

Get started free