AutomationFlowsEmail & Gmail › Send Missed Appointment Rescheduling Emails with Webhook and Gmail

Send Missed Appointment Rescheduling Emails with Webhook and Gmail

ByLocal Ops Kit @localopskit on n8n.io

This workflow receives missed-appointment events via a webhook, validates and filters them, then sends a single rescheduling email through Gmail and returns a JSON acknowledgement to the caller. Receives a POST webhook request containing appointment and contact details.…

Webhook trigger★★★★☆ complexity9 nodesGmail
Email & Gmail Trigger: Webhook Nodes: 9 Complexity: ★★★★☆ Added:

This workflow corresponds to n8n.io template #16155 — 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
{
  "name": "Send a rescheduling email after a missed appointment",
  "tags": [],
  "nodes": [
    {
      "id": "overview-note",
      "name": "Workflow guide",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -520,
        -320
      ],
      "parameters": {
        "color": 4,
        "width": 520,
        "height": 580,
        "content": "## Send a rescheduling email after a missed appointment\n\nThis workflow receives a missed-appointment webhook, validates the event, blocks ineligible contacts, sends one rescheduling email through Gmail, and returns a JSON acknowledgement.\n\n### Who it is for\n\nLocal businesses, agencies, and operators who receive appointment status updates from a CRM or scheduling system.\n\n### Setup\n\n1. Open **Configure recovery message** and set the business name, booking URL, and subject.\n2. Connect a customer-owned Gmail credential to **Send rescheduling email**.\n3. Send the example payload below to the test webhook.\n4. Confirm that non-missed appointments and contacts with `transactional_contact_allowed: false` do not send.\n5. Activate only after the business approves the message and data flow.\n\nThe imported workflow is inactive. Use a contact you control for testing."
      },
      "typeVersion": 1
    },
    {
      "id": "payload-note",
      "name": "Test payload",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -520,
        300
      ],
      "parameters": {
        "color": 7,
        "width": 440,
        "height": 430,
        "content": "## Example webhook payload\n\n```json\n{\n  \"event_id\": \"evt_test_001\",\n  \"contact\": {\n    \"name\": \"Test Customer\",\n    \"email\": \"operator-controlled@example.com\",\n    \"transactional_contact_allowed\": true\n  },\n  \"appointment\": {\n    \"id\": \"apt_test_001\",\n    \"status\": \"missed\"\n  }\n}\n```\n\nUse a stable, unique `event_id`. For production, add a Data Store lookup if your email provider does not support idempotency."
      },
      "typeVersion": 1
    },
    {
      "id": "missed-webhook",
      "name": "Receive missed appointment",
      "type": "n8n-nodes-base.webhook",
      "position": [
        40,
        0
      ],
      "parameters": {
        "path": "missed-appointment-recovery",
        "options": {},
        "httpMethod": "POST",
        "responseMode": "responseNode"
      },
      "typeVersion": 2
    },
    {
      "id": "configuration",
      "name": "Configure recovery message",
      "type": "n8n-nodes-base.set",
      "position": [
        280,
        0
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "business-name",
              "name": "business_name",
              "type": "string",
              "value": "Your Business"
            },
            {
              "id": "booking-url",
              "name": "booking_url",
              "type": "string",
              "value": "https://example.com/book"
            },
            {
              "id": "email-subject",
              "name": "email_subject",
              "type": "string",
              "value": "Would you like to reschedule?"
            }
          ]
        },
        "includeOtherFields": true
      },
      "typeVersion": 3.4
    },
    {
      "id": "prepare",
      "name": "Validate event and prepare email",
      "type": "n8n-nodes-base.code",
      "position": [
        520,
        0
      ],
      "parameters": {
        "jsCode": "const p = $json.body || $json;\nconst required = [p.event_id, p.contact?.email, p.appointment?.id];\nif (required.some((value) => !value)) {\n  throw new Error('Missing event_id, contact.email, or appointment.id');\n}\n\nconst status = String(p.appointment.status || '').toLowerCase();\nconst blocked = p.contact.transactional_contact_allowed === false || status !== 'missed';\nconst greeting = p.contact.name ? `Hi ${p.contact.name},` : 'Hi there,';\nconst message = `${greeting}\\n\\nWe missed you at your appointment with ${$json.business_name}. You can choose a new time here: ${$json.booking_url}\\n\\nReply to this email if you need help rescheduling.`;\n\nreturn [{\n  json: {\n    event_id: p.event_id,\n    appointment_id: p.appointment.id,\n    contact_email: p.contact.email,\n    blocked,\n    email_subject: $json.email_subject,\n    message\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "allowed",
      "name": "Is recovery allowed?",
      "type": "n8n-nodes-base.if",
      "position": [
        760,
        0
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "allowed-condition",
              "operator": {
                "type": "boolean",
                "operation": "equals"
              },
              "leftValue": "={{ $json.blocked }}",
              "rightValue": false
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "send",
      "name": "Send rescheduling email",
      "type": "n8n-nodes-base.gmail",
      "onError": "continueErrorOutput",
      "position": [
        1000,
        -100
      ],
      "parameters": {
        "sendTo": "={{ $json.contact_email }}",
        "message": "={{ $json.message }}",
        "options": {},
        "subject": "={{ $json.email_subject }}",
        "emailType": "text"
      },
      "typeVersion": 2.1
    },
    {
      "id": "response",
      "name": "Return webhook acknowledgement",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        1240,
        0
      ],
      "parameters": {
        "options": {},
        "respondWith": "json",
        "responseBody": "={{ { accepted: true, eventId: $json.event_id, blocked: $json.blocked || false } }}"
      },
      "typeVersion": 1.4
    },
    {
      "id": "safeguards-note",
      "name": "Production safeguards",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        760,
        260
      ],
      "parameters": {
        "color": 7,
        "width": 420,
        "height": 300,
        "content": "## Production safeguards\n\n- Re-check appointment status before any delayed send.\n- Use a Data Store or provider idempotency key to suppress duplicate event IDs.\n- Keep the message transactional; do not add unrelated promotions.\n- Connect credentials owned by the end customer.\n- Review failed executions and provide a human support route."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "connections": {
    "Is recovery allowed?": {
      "main": [
        [
          {
            "node": "Send rescheduling email",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Return webhook acknowledgement",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send rescheduling email": {
      "main": [
        [
          {
            "node": "Return webhook acknowledgement",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Return webhook acknowledgement",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Configure recovery message": {
      "main": [
        [
          {
            "node": "Validate event and prepare email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Receive missed appointment": {
      "main": [
        [
          {
            "node": "Configure recovery message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Validate event and prepare email": {
      "main": [
        [
          {
            "node": "Is recovery allowed?",
            "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

This workflow receives missed-appointment events via a webhook, validates and filters them, then sends a single rescheduling email through Gmail and returns a JSON acknowledgement to the caller. Receives a POST webhook request containing appointment and contact details.…

Source: https://n8n.io/workflows/16155/ — 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

Automate WhatsApp communication for recruitment agencies with an interactive, structured customer experience. This workflow handles pricing inquiries, request submissions, tracking, complaints, and hu

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

Code. Uses googleSheets, gmail, supabase, stickyNote. Webhook trigger; 51 nodes.

Google Sheets, Gmail, Supabase +1
Email & Gmail

This template turns Podium's conversation inbox into a full sales CRM with a custom funnel, AI message classification, automated drip follow-ups, daily admin reports, and a live Kanban dashboard. Six

HTTP Request, Google Sheets, Gmail
Email & Gmail

Suspicious_login_detection. Uses postgres, httpRequest, noOp, html. Webhook trigger; 43 nodes.

Postgres, HTTP Request, Gmail +1
Email & Gmail

This n8n workflow is designed for security monitoring and incident response when suspicious login events are detected. It can be initiated either manually from within the n8n UI for testing or automat

Postgres, HTTP Request, Gmail +1