AutomationFlowsEmail & Gmail › Handle Calendly Bookings, Cancellations and Reschedules with Gmail, Google…

Handle Calendly Bookings, Cancellations and Reschedules with Gmail, Google…

Original n8n title: Handle Calendly Bookings, Cancellations and Reschedules with Gmail, Google Calendar, Sheets and Slack

ByManu @manu on n8n.io

Complete Calendly automation that handles confirmations, cancellations and reschedules in a single workflow. WHAT IT DOES:

Webhook trigger★★★★☆ complexity27 nodesGoogle SheetsGoogle CalendarSlackGmail
Email & Gmail Trigger: Webhook Nodes: 27 Complexity: ★★★★☆ Added:

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

This workflow follows the Gmail → Google Calendar 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
{
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "nodes": [
    {
      "id": "8e9cbd41-5f6f-4209-bc9d-b924925c2d25",
      "name": "Calendly Webhook",
      "type": "n8n-nodes-base.webhook",
      "position": [
        -1280,
        -848
      ],
      "parameters": {
        "path": "calendly-webhook",
        "options": {
          "responseData": "allEntries"
        },
        "httpMethod": "POST"
      },
      "typeVersion": 2
    },
    {
      "id": "decdb973-67e1-479a-9314-8f8231b52fc5",
      "name": "Parse Calendly Event",
      "type": "n8n-nodes-base.code",
      "position": [
        -1040,
        -848
      ],
      "parameters": {
        "jsCode": "// Robust parser for Calendly API v1 and v2\nconst payload = $input.item.json.body || $input.item.json;\nconst event = payload.event || 'invitee.created';\nconst data = payload.payload || payload;\n\n// Extract invitee data\nconst invitee = data.invitee || data;\nconst eventDetails = data.event || data.scheduled_event || {};\nconst questions = data.questions_and_answers || invitee.questions_and_answers || [];\n\n// Process custom form answers\nconst customAnswers = {};\nquestions.forEach(q => {\n  customAnswers[q.question] = q.answer;\n});\n\n// Extract all relevant data\nconst email = invitee.email || '';\nconst name = invitee.name || 'Guest';\nconst startTime = eventDetails.start_time || invitee.start_time || '';\nconst endTime = eventDetails.end_time || invitee.end_time || '';\nconst timezone = invitee.timezone || 'UTC';\nconst meetingUrl = eventDetails.location?.join_url || invitee.meeting_url || '';\nconst eventType = eventDetails.event_type?.name || eventDetails.name || 'Meeting';\nconst cancelUrl = invitee.cancel_url || '';\nconst rescheduleUrl = invitee.reschedule_url || '';\n\n// Determine event category\nlet eventCategory = 'created';\nif (event.includes('canceled')) eventCategory = 'canceled';\nif (event.includes('rescheduled')) eventCategory = 'rescheduled';\n\n// Format dates for display\nconst startDate = new Date(startTime);\nconst formattedDate = startDate.toLocaleDateString('en-US', {\n  weekday: 'long',\n  year: 'numeric',\n  month: 'long',\n  day: 'numeric',\n  timeZone: timezone\n});\nconst formattedTime = startDate.toLocaleTimeString('en-US', {\n  hour: '2-digit',\n  minute: '2-digit',\n  timeZone: timezone\n});\n\nreturn {\n  json: {\n    // Event metadata\n    eventCategory: eventCategory,\n    eventType: event,\n    processedAt: new Date().toISOString(),\n    \n    // Invitee data\n    email: email,\n    name: name,\n    timezone: timezone,\n    \n    // Meeting data\n    meetingName: eventType,\n    startTime: startTime,\n    endTime: endTime,\n    startTimeISO: startTime,\n    formattedDate: formattedDate,\n    formattedTime: formattedTime,\n    meetingUrl: meetingUrl,\n    cancelUrl: cancelUrl,\n    rescheduleUrl: rescheduleUrl,\n    \n    // Custom answers\n    customAnswers: customAnswers,\n    \n    // Unique ID for tracking\n    eventId: `CAL-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "91ebc749-da04-49d4-afa4-18df349bbf07",
      "name": "Event Router",
      "type": "n8n-nodes-base.switch",
      "position": [
        -800,
        -864
      ],
      "parameters": {
        "rules": {
          "rules": [
            {
              "value2": "created"
            },
            {
              "value2": "canceled"
            },
            {
              "value2": "rescheduled"
            }
          ]
        },
        "value1": "={{ $json.eventCategory }}",
        "dataType": "string"
      },
      "typeVersion": 2
    },
    {
      "id": "00db7ebb-0435-48ba-b99d-7161e467745c",
      "name": "Log to Google Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        -464,
        -1008
      ],
      "parameters": {
        "columns": {
          "value": {
            "Date": "={{ $json.formattedDate }}",
            "Name": "={{ $json.name }}",
            "Time": "={{ $json.formattedTime }}",
            "Email": "={{ $json.email }}",
            "Status": "Confirmed",
            "Event ID": "={{ $json.eventId }}",
            "Timezone": "={{ $json.timezone }}",
            "Date Logged": "={{ $json.processedAt }}",
            "Meeting URL": "={{ $json.meetingUrl }}",
            "Meeting Type": "={{ $json.meetingName }}"
          },
          "mappingMode": "defineBelow"
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "Bookings"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "YOUR_DOCUMENT_ID"
        }
      },
      "typeVersion": 4
    },
    {
      "id": "369484ae-7487-4978-ac6e-f31aedb9b147",
      "name": "Create Calendar Event",
      "type": "n8n-nodes-base.googleCalendar",
      "position": [
        -224,
        -1008
      ],
      "parameters": {
        "end": "={{ $('Parse Calendly Event').item.json.endTime }}",
        "start": "={{ $('Parse Calendly Event').item.json.startTime }}",
        "calendar": {
          "__rl": true,
          "mode": "list",
          "value": "primary"
        },
        "additionalFields": {
          "summary": "={{ $('Parse Calendly Event').item.json.meetingName }} - {{ $('Parse Calendly Event').item.json.name }}",
          "description": "Meeting with {{ $('Parse Calendly Event').item.json.name }} ({{ $('Parse Calendly Event').item.json.email }})\n\nJoin: {{ $('Parse Calendly Event').item.json.meetingUrl }}"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "cefb5f50-286c-458d-ac13-c8bbbed78623",
      "name": "Slack - New Booking",
      "type": "n8n-nodes-base.slack",
      "position": [
        16,
        -1008
      ],
      "parameters": {
        "text": ":calendar: *New Meeting Booked*",
        "otherOptions": {
          "includeLinkToWorkflow": false
        }
      },
      "typeVersion": 2
    },
    {
      "id": "b7e4ac62-c2cd-4a18-b5bd-0e7954e5a9b8",
      "name": "Prepare Confirmation Email",
      "type": "n8n-nodes-base.code",
      "position": [
        256,
        -1008
      ],
      "parameters": {
        "jsCode": "// CONFIG - Customize these values\nconst CONFIG = {\n  companyName: 'Your Company',\n  primaryColor: '#10b981',\n  secondaryColor: '#667eea',\n  logoUrl: '', // Optional: Your logo URL\n  footerText: 'Thank you for booking with us'\n};\n\nconst data = $('Parse Calendly Event').first().json;\n\nconst emailHtml = `\n<!DOCTYPE html>\n<html>\n<head>\n  <meta charset=\"UTF-8\">\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n</head>\n<body style=\"margin:0;padding:0;font-family:'Segoe UI',Roboto,Arial,sans-serif;background:#f4f7fa;\">\n  <table width=\"100%\" cellpadding=\"0\" cellspacing=\"0\" style=\"background:#f4f7fa;padding:40px 20px;\">\n    <tr>\n      <td align=\"center\">\n        <table width=\"600\" cellpadding=\"0\" cellspacing=\"0\" style=\"background:#ffffff;border-radius:16px;box-shadow:0 4px 20px rgba(0,0,0,0.08);overflow:hidden;\">\n          \n          <!-- Header -->\n          <tr>\n            <td style=\"background:linear-gradient(135deg, ${CONFIG.primaryColor} 0%, ${CONFIG.secondaryColor} 100%);padding:40px 30px;text-align:center;\">\n              ${CONFIG.logoUrl ? `<img src=\"${CONFIG.logoUrl}\" alt=\"Logo\" style=\"max-height:50px;margin-bottom:15px;\">` : ''}\n              <h1 style=\"margin:0;color:#ffffff;font-size:28px;font-weight:600;\">Meeting Confirmed!</h1>\n            </td>\n          </tr>\n          \n          <!-- Content -->\n          <tr>\n            <td style=\"padding:40px 30px;\">\n              <h2 style=\"margin:0 0 20px;color:#1a202c;font-size:22px;\">Hi ${data.name},</h2>\n              <p style=\"color:#4a5568;font-size:16px;line-height:1.7;margin:0 0 25px;\">Your meeting with <strong>${CONFIG.companyName}</strong> has been confirmed.</p>\n              \n              <!-- Meeting Details Card -->\n              <div style=\"background:linear-gradient(135deg, #f0fdf4 0%, #ecfdf5 100%);border-radius:12px;padding:25px;margin:25px 0;border-left:4px solid ${CONFIG.primaryColor};\">\n                <table width=\"100%\" cellpadding=\"0\" cellspacing=\"0\">\n                  <tr>\n                    <td style=\"padding:8px 0;\">\n                      <span style=\"color:#166534;font-size:17px;font-weight:600;\">${data.formattedDate}</span>\n                    </td>\n                  </tr>\n                  <tr>\n                    <td style=\"padding:8px 0;\">\n                      <span style=\"color:#166534;font-size:17px;font-weight:600;\">${data.formattedTime}</span>\n                    </td>\n                  </tr>\n                  <tr>\n                    <td style=\"padding:8px 0;\">\n                      <span style=\"color:#166534;font-size:16px;\">${data.meetingName}</span>\n                    </td>\n                  </tr>\n                </table>\n              </div>\n              \n              <!-- Join Button -->\n              ${data.meetingUrl ? `\n              <div style=\"text-align:center;margin:30px 0;\">\n                <a href=\"${data.meetingUrl}\" style=\"display:inline-block;background:linear-gradient(135deg, ${CONFIG.secondaryColor} 0%, #5a67d8 100%);color:#ffffff;text-decoration:none;padding:16px 45px;border-radius:10px;font-size:16px;font-weight:600;box-shadow:0 4px 15px rgba(102,126,234,0.4);\">\n                  Join Meeting\n                </a>\n              </div>\n              ` : ''}\n              \n              <!-- Action Links -->\n              <div style=\"background:#f7fafc;border-radius:10px;padding:20px;margin:25px 0;text-align:center;\">\n                <p style=\"color:#718096;font-size:14px;margin:0 0 15px;\">Need to make changes?</p>\n                <table width=\"100%\" cellpadding=\"0\" cellspacing=\"0\">\n                  <tr>\n                    ${data.rescheduleUrl ? `<td style=\"text-align:center;\"><a href=\"${data.rescheduleUrl}\" style=\"color:${CONFIG.secondaryColor};font-size:14px;text-decoration:none;font-weight:500;\">Reschedule</a></td>` : ''}\n                    ${data.cancelUrl ? `<td style=\"text-align:center;\"><a href=\"${data.cancelUrl}\" style=\"color:#e53e3e;font-size:14px;text-decoration:none;font-weight:500;\">Cancel</a></td>` : ''}\n                  </tr>\n                </table>\n              </div>\n              \n              <!-- Tips -->\n              <div style=\"border-top:1px solid #e2e8f0;padding-top:25px;margin-top:25px;\">\n                <p style=\"color:#718096;font-size:14px;line-height:1.6;margin:0;\">\n                  <strong>Tip:</strong> Join the meeting 2-3 minutes before the scheduled time.\n                </p>\n              </div>\n            </td>\n          </tr>\n          \n          <!-- Footer -->\n          <tr>\n            <td style=\"background:#f7fafc;padding:25px 30px;text-align:center;border-top:1px solid #e2e8f0;\">\n              <p style=\"margin:0 0 10px;color:#718096;font-size:13px;\">${CONFIG.footerText}</p>\n              <p style=\"margin:0;color:#a0aec0;font-size:12px;\">${new Date().getFullYear()} ${CONFIG.companyName}. All rights reserved.</p>\n            </td>\n          </tr>\n          \n        </table>\n      </td>\n    </tr>\n  </table>\n</body>\n</html>\n`;\n\nreturn {\n  json: {\n    to: data.email,\n    subject: `Meeting Confirmed - ${data.formattedDate} at ${data.formattedTime}`,\n    htmlContent: emailHtml,\n    eventId: data.eventId\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "cf36773b-1710-4032-ab9c-b56c0eb53446",
      "name": "Send Confirmation Email",
      "type": "n8n-nodes-base.gmail",
      "position": [
        496,
        -1008
      ],
      "parameters": {
        "sendTo": "={{ $json.to }}",
        "message": "={{ $json.htmlContent }}",
        "options": {
          "appendAttribution": false
        },
        "subject": "={{ $json.subject }}"
      },
      "typeVersion": 2
    },
    {
      "id": "5dcb1944-e95c-4432-a83b-3cf9db38903c",
      "name": "Log Cancellation",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        -448,
        -624
      ],
      "parameters": {
        "columns": {
          "value": {
            "Date": "={{ $('Parse Calendly Event').item.json.formattedDate }}",
            "Name": "={{ $('Parse Calendly Event').item.json.name }}",
            "Time": "={{ $('Parse Calendly Event').item.json.formattedTime }}",
            "Email": "={{ $('Parse Calendly Event').item.json.email }}",
            "Status": "Canceled",
            "Event ID": "={{ $('Parse Calendly Event').item.json.eventId }}",
            "Timezone": "={{ $('Parse Calendly Event').item.json.timezone }}",
            "Date Logged": "={{ $('Parse Calendly Event').item.json.processedAt }}",
            "Meeting URL": "={{ $('Parse Calendly Event').item.json.meetingUrl }}",
            "Meeting Type": "={{ $('Parse Calendly Event').item.json.meetingName }}"
          },
          "mappingMode": "defineBelow"
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "Bookings"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "YOUR_DOCUMENT_ID"
        }
      },
      "typeVersion": 4
    },
    {
      "id": "4fb3f3f9-f83b-4aba-a0b0-58b2377b850c",
      "name": "Slack - Cancellation",
      "type": "n8n-nodes-base.slack",
      "position": [
        -208,
        -624
      ],
      "parameters": {
        "text": ":x: *Meeting Canceled*",
        "otherOptions": {
          "includeLinkToWorkflow": false
        }
      },
      "typeVersion": 2
    },
    {
      "id": "37bc05c0-2061-4a26-ace8-8ed0a674e21d",
      "name": "Prepare Cancellation Email",
      "type": "n8n-nodes-base.code",
      "position": [
        32,
        -624
      ],
      "parameters": {
        "jsCode": "// CONFIG - Customize these values\nconst CONFIG = {\n  companyName: 'Your Company',\n  primaryColor: '#ef4444',\n  calendlyUrl: 'https://calendly.com/your-username' // Your Calendly link\n};\n\nconst data = $('Parse Calendly Event').first().json;\n\nconst emailHtml = `\n<!DOCTYPE html>\n<html>\n<head>\n  <meta charset=\"UTF-8\">\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n</head>\n<body style=\"margin:0;padding:0;font-family:'Segoe UI',Roboto,Arial,sans-serif;background:#f4f7fa;\">\n  <table width=\"100%\" cellpadding=\"0\" cellspacing=\"0\" style=\"background:#f4f7fa;padding:40px 20px;\">\n    <tr>\n      <td align=\"center\">\n        <table width=\"600\" cellpadding=\"0\" cellspacing=\"0\" style=\"background:#ffffff;border-radius:16px;box-shadow:0 4px 20px rgba(0,0,0,0.08);overflow:hidden;\">\n          \n          <!-- Header -->\n          <tr>\n            <td style=\"background:${CONFIG.primaryColor};padding:40px 30px;text-align:center;\">\n              <h1 style=\"margin:0;color:#ffffff;font-size:28px;font-weight:600;\">Meeting Canceled</h1>\n            </td>\n          </tr>\n          \n          <!-- Content -->\n          <tr>\n            <td style=\"padding:40px 30px;\">\n              <h2 style=\"margin:0 0 20px;color:#1a202c;font-size:22px;\">Hi ${data.name},</h2>\n              <p style=\"color:#4a5568;font-size:16px;line-height:1.7;margin:0 0 25px;\">Your meeting with <strong>${CONFIG.companyName}</strong> has been canceled.</p>\n              \n              <!-- Cancelled Meeting Details -->\n              <div style=\"background:#fef2f2;border-radius:12px;padding:25px;margin:25px 0;border-left:4px solid ${CONFIG.primaryColor};\">\n                <table width=\"100%\" cellpadding=\"0\" cellspacing=\"0\">\n                  <tr>\n                    <td style=\"padding:8px 0;\">\n                      <span style=\"color:#991b1b;font-size:16px;\">${data.formattedDate}</span>\n                    </td>\n                  </tr>\n                  <tr>\n                    <td style=\"padding:8px 0;\">\n                      <span style=\"color:#991b1b;font-size:16px;\">${data.formattedTime}</span>\n                    </td>\n                  </tr>\n                  <tr>\n                    <td style=\"padding:8px 0;\">\n                      <span style=\"color:#991b1b;font-size:16px;\">${data.meetingName}</span>\n                    </td>\n                  </tr>\n                </table>\n              </div>\n              \n              <!-- Reschedule Button -->\n              <div style=\"text-align:center;margin:30px 0;\">\n                <p style=\"color:#4a5568;font-size:16px;margin:0 0 20px;\">Would you like to schedule another meeting?</p>\n                <a href=\"${CONFIG.calendlyUrl}\" style=\"display:inline-block;background:#10b981;color:#ffffff;text-decoration:none;padding:16px 45px;border-radius:10px;font-size:16px;font-weight:600;box-shadow:0 4px 15px rgba(16,185,129,0.4);\">\n                  Book New Meeting\n                </a>\n              </div>\n            </td>\n          </tr>\n          \n          <!-- Footer -->\n          <tr>\n            <td style=\"background:#f7fafc;padding:25px 30px;text-align:center;border-top:1px solid #e2e8f0;\">\n              <p style=\"margin:0;color:#a0aec0;font-size:12px;\">${new Date().getFullYear()} ${CONFIG.companyName}. All rights reserved.</p>\n            </td>\n          </tr>\n          \n        </table>\n      </td>\n    </tr>\n  </table>\n</body>\n</html>\n`;\n\nreturn {\n  json: {\n    to: data.email,\n    subject: `Meeting Canceled - ${data.formattedDate}`,\n    htmlContent: emailHtml\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "9b9b93da-2e01-48ab-9c68-a3cbbcc71abd",
      "name": "Send Cancellation Email",
      "type": "n8n-nodes-base.gmail",
      "position": [
        272,
        -624
      ],
      "parameters": {
        "sendTo": "={{ $json.to }}",
        "message": "={{ $json.htmlContent }}",
        "options": {
          "appendAttribution": false
        },
        "subject": "={{ $json.subject }}"
      },
      "typeVersion": 2
    },
    {
      "id": "0d1e0984-8f1c-4b3e-af68-e5ea6cce2d2c",
      "name": "Log Reschedule",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        -464,
        -256
      ],
      "parameters": {
        "columns": {
          "value": {
            "Date": "={{ $('Parse Calendly Event').item.json.formattedDate }}",
            "Name": "={{ $('Parse Calendly Event').item.json.name }}",
            "Time": "={{ $('Parse Calendly Event').item.json.formattedTime }}",
            "Email": "={{ $('Parse Calendly Event').item.json.email }}",
            "Status": "Rescheduled",
            "Event ID": "={{ $('Parse Calendly Event').item.json.eventId }}",
            "Timezone": "={{ $('Parse Calendly Event').item.json.timezone }}",
            "Date Logged": "={{ $('Parse Calendly Event').item.json.processedAt }}",
            "Meeting URL": "={{ $('Parse Calendly Event').item.json.meetingUrl }}",
            "Meeting Type": "={{ $('Parse Calendly Event').item.json.meetingName }}"
          },
          "mappingMode": "defineBelow"
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "Bookings"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "YOUR_DOCUMENT_ID"
        }
      },
      "typeVersion": 4
    },
    {
      "id": "0cd3d70a-22ee-4e8c-8b1d-32f63e1fbd30",
      "name": "Slack - Rescheduled",
      "type": "n8n-nodes-base.slack",
      "position": [
        -224,
        -256
      ],
      "parameters": {
        "text": ":arrows_counterclockwise: *Meeting Rescheduled*",
        "otherOptions": {
          "includeLinkToWorkflow": false
        }
      },
      "typeVersion": 2
    },
    {
      "id": "6075cd53-0a71-4fee-bb63-968790babc82",
      "name": "Prepare Reschedule Email",
      "type": "n8n-nodes-base.code",
      "position": [
        16,
        -256
      ],
      "parameters": {
        "jsCode": "// CONFIG - Customize these values\nconst CONFIG = {\n  companyName: 'Your Company',\n  primaryColor: '#f59e0b',\n  secondaryColor: '#667eea'\n};\n\nconst data = $('Parse Calendly Event').first().json;\n\nconst emailHtml = `\n<!DOCTYPE html>\n<html>\n<head>\n  <meta charset=\"UTF-8\">\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n</head>\n<body style=\"margin:0;padding:0;font-family:'Segoe UI',Roboto,Arial,sans-serif;background:#f4f7fa;\">\n  <table width=\"100%\" cellpadding=\"0\" cellspacing=\"0\" style=\"background:#f4f7fa;padding:40px 20px;\">\n    <tr>\n      <td align=\"center\">\n        <table width=\"600\" cellpadding=\"0\" cellspacing=\"0\" style=\"background:#ffffff;border-radius:16px;box-shadow:0 4px 20px rgba(0,0,0,0.08);overflow:hidden;\">\n          \n          <!-- Header -->\n          <tr>\n            <td style=\"background:linear-gradient(135deg, ${CONFIG.primaryColor} 0%, #d97706 100%);padding:40px 30px;text-align:center;\">\n              <h1 style=\"margin:0;color:#ffffff;font-size:28px;font-weight:600;\">Meeting Rescheduled</h1>\n            </td>\n          </tr>\n          \n          <!-- Content -->\n          <tr>\n            <td style=\"padding:40px 30px;\">\n              <h2 style=\"margin:0 0 20px;color:#1a202c;font-size:22px;\">Hi ${data.name},</h2>\n              <p style=\"color:#4a5568;font-size:16px;line-height:1.7;margin:0 0 25px;\">Your meeting with <strong>${CONFIG.companyName}</strong> has been rescheduled.</p>\n              \n              <!-- New Meeting Details -->\n              <div style=\"background:#fffbeb;border-radius:12px;padding:25px;margin:25px 0;border-left:4px solid ${CONFIG.primaryColor};\">\n                <p style=\"color:#92400e;font-size:14px;font-weight:600;margin:0 0 15px;\">NEW DATE AND TIME:</p>\n                <table width=\"100%\" cellpadding=\"0\" cellspacing=\"0\">\n                  <tr>\n                    <td style=\"padding:8px 0;\">\n                      <span style=\"color:#92400e;font-size:18px;font-weight:600;\">${data.formattedDate}</span>\n                    </td>\n                  </tr>\n                  <tr>\n                    <td style=\"padding:8px 0;\">\n                      <span style=\"color:#92400e;font-size:18px;font-weight:600;\">${data.formattedTime}</span>\n                    </td>\n                  </tr>\n                  <tr>\n                    <td style=\"padding:8px 0;\">\n                      <span style=\"color:#92400e;font-size:16px;\">${data.meetingName}</span>\n                    </td>\n                  </tr>\n                </table>\n              </div>\n              \n              <!-- Join Button -->\n              ${data.meetingUrl ? `\n              <div style=\"text-align:center;margin:30px 0;\">\n                <a href=\"${data.meetingUrl}\" style=\"display:inline-block;background:linear-gradient(135deg, ${CONFIG.secondaryColor} 0%, #5a67d8 100%);color:#ffffff;text-decoration:none;padding:16px 45px;border-radius:10px;font-size:16px;font-weight:600;box-shadow:0 4px 15px rgba(102,126,234,0.4);\">\n                  Join Meeting\n                </a>\n              </div>\n              ` : ''}\n              \n              <!-- Action Links -->\n              <div style=\"background:#f7fafc;border-radius:10px;padding:20px;margin:25px 0;text-align:center;\">\n                <p style=\"color:#718096;font-size:14px;margin:0 0 15px;\">Need to make more changes?</p>\n                <table width=\"100%\" cellpadding=\"0\" cellspacing=\"0\">\n                  <tr>\n                    ${data.rescheduleUrl ? `<td style=\"text-align:center;\"><a href=\"${data.rescheduleUrl}\" style=\"color:${CONFIG.secondaryColor};font-size:14px;text-decoration:none;font-weight:500;\">Reschedule</a></td>` : ''}\n                    ${data.cancelUrl ? `<td style=\"text-align:center;\"><a href=\"${data.cancelUrl}\" style=\"color:#e53e3e;font-size:14px;text-decoration:none;font-weight:500;\">Cancel</a></td>` : ''}\n                  </tr>\n                </table>\n              </div>\n            </td>\n          </tr>\n          \n          <!-- Footer -->\n          <tr>\n            <td style=\"background:#f7fafc;padding:25px 30px;text-align:center;border-top:1px solid #e2e8f0;\">\n              <p style=\"margin:0;color:#a0aec0;font-size:12px;\">${new Date().getFullYear()} ${CONFIG.companyName}. All rights reserved.</p>\n            </td>\n          </tr>\n          \n        </table>\n      </td>\n    </tr>\n  </table>\n</body>\n</html>\n`;\n\nreturn {\n  json: {\n    to: data.email,\n    subject: `Meeting Rescheduled - ${data.formattedDate} at ${data.formattedTime}`,\n    htmlContent: emailHtml\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "0a0f4d36-ca44-4d37-ad4b-d36dc5698ee0",
      "name": "Send Reschedule Email",
      "type": "n8n-nodes-base.gmail",
      "position": [
        256,
        -256
      ],
      "parameters": {
        "sendTo": "={{ $json.to }}",
        "message": "={{ $json.htmlContent }}",
        "options": {
          "appendAttribution": false
        },
        "subject": "={{ $json.subject }}"
      },
      "typeVersion": 2
    },
    {
      "id": "56506437-97ed-43e2-a09c-e050f631e0f9",
      "name": "Done - Confirmation",
      "type": "n8n-nodes-base.noOp",
      "position": [
        736,
        -1008
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "d27edce0-051a-42ca-9d56-57b2e305916d",
      "name": "Done - Cancellation",
      "type": "n8n-nodes-base.noOp",
      "position": [
        512,
        -624
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "44225c03-1919-4767-91cb-fc69c13d72ba",
      "name": "Done - Reschedule",
      "type": "n8n-nodes-base.noOp",
      "position": [
        496,
        -256
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "155707a6-2b04-4e54-92de-8a59256d7628",
      "name": "Webhook",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1312,
        -976
      ],
      "parameters": {
        "color": 5,
        "width": 720,
        "height": 312,
        "content": "## Webhook & routing\n\nReceives Calendly events and routes by type."
      },
      "typeVersion": 1
    },
    {
      "id": "120c5a36-68ce-4bf7-8db5-173492c2fc28",
      "name": "New Booking",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -496,
        -1120
      ],
      "parameters": {
        "color": 3,
        "width": 1480,
        "height": 296,
        "content": "## New booking\n\nLogs, syncs calendar, notifies Slack, sends confirmation."
      },
      "typeVersion": 1
    },
    {
      "id": "2d5fc67f-1ac9-4889-9605-a51b1f313551",
      "name": "Cancellation",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -496,
        -752
      ],
      "parameters": {
        "color": 4,
        "width": 1480,
        "height": 280,
        "content": "## Cancellation\n\nLogs cancellation, alerts team, notifies attendee."
      },
      "typeVersion": 1
    },
    {
      "id": "8380eac3-ef05-4760-998e-e63c23ddd2f0",
      "name": "Reschedule",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -480,
        -384
      ],
      "parameters": {
        "color": 6,
        "width": 1464,
        "height": 296,
        "content": "## Reschedule\n\nLogs changes, alerts team, sends updated details."
      },
      "typeVersion": 1
    },
    {
      "id": "db823055-c7c8-4920-8acb-22ca06a1b781",
      "name": "Format Error1",
      "type": "n8n-nodes-base.code",
      "position": [
        -1280,
        -240
      ],
      "parameters": {
        "jsCode": "// Capture error information\nconst error = $input.item.json;\n\nreturn {\n  json: {\n    errorTime: new Date().toISOString(),\n    errorMessage: error.message || 'Unknown error',\n    errorNode: error.node?.name || 'Unknown',\n    workflowName: 'Calendly Booking Automation',\n    severity: 'HIGH'\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "4de6021c-e37e-4de2-80df-0549518e2840",
      "name": "Slack - Error Alert1",
      "type": "n8n-nodes-base.slack",
      "position": [
        -960,
        -240
      ],
      "parameters": {
        "text": ":rotating_light: *Workflow Error*",
        "otherOptions": {
          "includeLinkToWorkflow": true
        }
      },
      "typeVersion": 2
    },
    {
      "id": "2473c798-26a5-4e26-9728-2ef01143b431",
      "name": "Overview1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1792,
        -1120
      ],
      "parameters": {
        "color": 2,
        "width": 420,
        "height": 560,
        "content": "## Automate Calendly bookings with Gmail, Google Calendar, Sheets and Slack\n\nSyncs Calendly events to your calendar, logs to Sheets, sends confirmations, and alerts your team.\n\n### How it works\n\n1. **Receive** - Webhook captures Calendly events instantly\n2. **Route** - Detects event type: new booking, cancellation, or reschedule\n3. **Log** - Records all events to Google Sheets\n4. **Sync** - Creates/updates Google Calendar events\n5. **Notify** - Sends Slack alerts to your team\n6. **Confirm** - Emails attendees with booking details\n\n### Setup steps\n\n1. **Calendly:** Create webhook pointing to this workflow URL\n2. **Connect:** Gmail, Google Calendar, Sheets, Slack\n3. **Create Sheet:** Tab named \"Bookings\"\n4. **Update IDs:** Replace YOUR_DOCUMENT_ID\n5. **Slack:** Configure #bookings and #errors channels\n6. **Test:** Create a test booking in Calendly"
      },
      "typeVersion": 1
    },
    {
      "id": "f29d5156-ba0d-4f4e-b942-6cfe95e37e6e",
      "name": "Errors1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1312,
        -352
      ],
      "parameters": {
        "color": 7,
        "width": 720,
        "height": 232,
        "content": "## Error handling\n\nCatches errors and alerts #errors channel."
      },
      "typeVersion": 1
    }
  ],
  "connections": {
    "Event Router": {
      "main": [
        [
          {
            "node": "Log to Google Sheets",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Log Cancellation",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Log Reschedule",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format Error1": {
      "main": [
        [
          {
            "node": "Slack - Error Alert1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Log Reschedule": {
      "main": [
        [
          {
            "node": "Slack - Rescheduled",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Calendly Webhook": {
      "main": [
        [
          {
            "node": "Parse Calendly Event",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Log Cancellation": {
      "main": [
        [
          {
            "node": "Slack - Cancellation",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Slack - New Booking": {
      "main": [
        [
          {
            "node": "Prepare Confirmation Email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Slack - Rescheduled": {
      "main": [
        [
          {
            "node": "Prepare Reschedule Email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Log to Google Sheets": {
      "main": [
        [
          {
            "node": "Create Calendar Event",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Calendly Event": {
      "main": [
        [
          {
            "node": "Event Router",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Slack - Cancellation": {
      "main": [
        [
          {
            "node": "Prepare Cancellation Email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create Calendar Event": {
      "main": [
        [
          {
            "node": "Slack - New Booking",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Reschedule Email": {
      "main": [
        [
          {
            "node": "Done - Reschedule",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Cancellation Email": {
      "main": [
        [
          {
            "node": "Done - Cancellation",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Confirmation Email": {
      "main": [
        [
          {
            "node": "Done - Confirmation",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Reschedule Email": {
      "main": [
        [
          {
            "node": "Send Reschedule Email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Cancellation Email": {
      "main": [
        [
          {
            "node": "Send Cancellation Email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Confirmation Email": {
      "main": [
        [
          {
            "node": "Send Confirmation Email",
            "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

Complete Calendly automation that handles confirmations, cancellations and reschedules in a single workflow. WHAT IT DOES:

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

More Email & Gmail workflows → · Browse all categories →

Related workflows

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

Email & Gmail

Sync your Google Calendar events with Google Sheets and get daily Slack summaries with meeting statistics. FEATURES:

Google Calendar Trigger, Google Sheets, Slack +3
Email & Gmail

Who is this for? This template is ideal for event organizers, conference managers, and community teams who need an automated participant management system. Perfect for workshops, conferences, meetups,

Google Sheets, HTTP Request, Gmail +1
Email & Gmail

Automatically generate, validate, and deliver professional course completion certificates with zero manual work — from webhook request to PDF delivery in seconds.

Gmail, Google Sheets, Error Trigger +4
Email & Gmail

Streamline and standardize your entire client onboarding process with a single end-to-end automation. 🚀📋 This workflow captures detailed client intake data via webhook, automatically creates a fully s

Slack, Asana, HTTP Request +4
Email & Gmail

Automate your GoHighLevel (GHL) client onboarding process from the moment a deal is marked as “Won.” This workflow seamlessly generates client folders in Google Drive, duplicates contract and kickoff

Google Drive, Slack, Gmail +2