{
  "id": "tiOBlM9vUVc82ZyC",
  "name": "AI Patient Follow-Up System: Auto-Send Welcome, Rebook and Follow-Up Emails with Claude",
  "tags": [],
  "nodes": [
    {
      "id": "8ec04286-ed4c-43cb-b74d-5b1e3febf221",
      "name": "Overview",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        0,
        0
      ],
      "parameters": {
        "color": 0,
        "width": 480,
        "height": 1184,
        "content": "## AI Patient Follow-Up System using Claude and Gmail\n\nStop manually chasing patients. This workflow reads every new patient intake submission, uses Claude AI to understand their situation, and automatically sends the right email -- a warm welcome for new patients, a re-booking nudge for lapsed ones, or a personalised follow-up for everyone else. High-priority re-booking cases also alert your clinic manager on Slack.\n\n### How it works\n\n1. A patient submits your intake form built into this workflow -- collecting their name, email, contact reason, appointment status, and any notes.\n2. Claude Sonnet reads the submission and decides the best action: send a welcome email, prompt them to re-book, or send a follow-up.\n3. Claude also writes the full personalised email body and subject line tailored to that patient.\n4. A Switch node routes the patient to the correct branch based on Claude's decision.\n5. New patients get a warm welcome email sent automatically via Gmail.\n6. Lapsed patients get a re-booking email, and your clinic manager gets a Slack alert to confirm the appointment.\n7. All other patients get a personalised follow-up email.\n8. Every patient communication is logged to Google Sheets with timestamp, action taken, and Claude's reasoning.\n\n### Setup steps\n\n- [ ] **Form link** -- Activate the workflow to generate your patient intake form URL. Share it on your website, in email signatures, or via SMS. No external form tool needed.\n- [ ] **Configure Settings node** -- Open Configure Clinic Settings and fill in your clinic name, Gmail sender address, Slack channel ID, booking link, and Google Sheets IDs.\n- [ ] **Gmail** -- Connect your Gmail account in Send Welcome Email, Send Rebook Email, and Send Follow-Up Email nodes.\n- [ ] **Claude AI** -- Click the Claude Sonnet sub-node under Analyse Patient Submission, add a new Anthropic credential, and paste your API key from console.anthropic.com.\n- [ ] **Slack** -- Connect your Slack account in Notify Clinic Manager and set your channel. Right-click and Disable this node if you do not use Slack.\n- [ ] **Google Sheets** -- Create a sheet called Communications Log with columns: Timestamp, Patient Name, Patient Email, Action, Urgency, Email Subject, Reason, Status. Connect your Google account in all three Log nodes.\n- [ ] **Customise Claude prompt** -- Open Build Patient Prompt and update the clinic description to match your practice type (dental, GP, physio, etc.).\n- [ ] Activate the workflow and submit a test form entry to verify all three branches work.\n\n### Customization\n\nAdd a fourth branch for urgent cases by adding a new output to the Switch node and checking the urgency field. Connect a phone-call trigger via Twilio for high-urgency patients. Swap the Form Trigger for a Google Sheets Trigger if you already collect intake data in a spreadsheet."
      },
      "typeVersion": 1
    },
    {
      "id": "99c3b222-b855-4589-a34f-4d7ec3f5c9db",
      "name": "Intake Section",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        496,
        80
      ],
      "parameters": {
        "color": 7,
        "width": 440,
        "height": 312,
        "content": "## Capture patient intake\n\nA built-in n8n form collects patient name, email, contact reason, appointment status, and notes. No third-party form tool needed -- the URL is generated automatically when the workflow is activated."
      },
      "typeVersion": 1
    },
    {
      "id": "f7a3d0cd-0be2-4c85-8d86-fff918ebeab3",
      "name": "AI Analysis Section",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        960,
        64
      ],
      "parameters": {
        "color": 7,
        "width": 644,
        "height": 532,
        "content": "## Analyse and write email with Claude AI\n\nClaude Sonnet reads the patient record and returns one structured decision: which action to take (welcome, rebook, or follow-up), the urgency level, a personalised email subject, a full plain-text email body, and a one-sentence reasoning.\n\nEdit the prompt in Build Patient Prompt to describe your clinic type and any additional context you want Claude to consider."
      },
      "typeVersion": 1
    },
    {
      "id": "d900bcbe-8f4b-4071-8061-e7360a5b4e42",
      "name": "Routing Section",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1632,
        48
      ],
      "parameters": {
        "color": 7,
        "width": 380,
        "height": 524,
        "content": "## Route by action\n\nA Switch node reads Claude's decision and routes each patient to one of three branches: Welcome (new patients), Rebook (lapsed patients), or Follow-Up (all others)."
      },
      "typeVersion": 1
    },
    {
      "id": "21c0ef74-7968-42e6-a901-21ef977b0b00",
      "name": "Branches Section",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2032,
        -48
      ],
      "parameters": {
        "color": 7,
        "width": 948,
        "height": 724,
        "content": "## Send email and log every communication\n\nEach branch sends a Claude-written plain-text email via Gmail and logs the result to Google Sheets.\n\nThe Rebook branch also sends a Slack alert to your clinic manager so they can personally confirm a new appointment time with the patient.\n\nSlack is optional -- right-click Notify Clinic Manager and Disable if unused."
      },
      "typeVersion": 1
    },
    {
      "id": "ab2cbf08-ec10-4a8b-a4dd-39b16c5a7386",
      "name": "Patient Intake Form",
      "type": "n8n-nodes-base.formTrigger",
      "position": [
        528,
        240
      ],
      "parameters": {
        "options": {},
        "formTitle": "Patient Intake Form",
        "formFields": {
          "values": [
            {
              "fieldLabel": "Full Name",
              "requiredField": true
            },
            {
              "fieldType": "email",
              "fieldLabel": "Email Address",
              "requiredField": true
            },
            {
              "fieldType": "dropdown",
              "fieldLabel": "Reason for Contact",
              "fieldOptions": {
                "values": [
                  {
                    "option": "New patient enquiry"
                  },
                  {
                    "option": "Book an appointment"
                  },
                  {
                    "option": "Re-book a missed appointment"
                  },
                  {
                    "option": "Follow-up after treatment"
                  },
                  {
                    "option": "General question"
                  }
                ]
              },
              "requiredField": true
            },
            {
              "fieldType": "dropdown",
              "fieldLabel": "When was your last appointment?",
              "fieldOptions": {
                "values": [
                  {
                    "option": "Never been -- I am a new patient"
                  },
                  {
                    "option": "Within the last 3 months"
                  },
                  {
                    "option": "3 to 6 months ago"
                  },
                  {
                    "option": "6 to 12 months ago"
                  },
                  {
                    "option": "More than a year ago"
                  }
                ]
              },
              "requiredField": true
            },
            {
              "fieldType": "textarea",
              "fieldLabel": "Additional notes (optional)"
            }
          ]
        },
        "responseMode": "lastNode",
        "formDescription": "Please fill in your details and we will be in touch shortly."
      },
      "typeVersion": 2.2
    },
    {
      "id": "5b9951ac-117d-43fe-97b0-f447725bfd02",
      "name": "Configure Clinic Settings",
      "type": "n8n-nodes-base.code",
      "position": [
        768,
        240
      ],
      "parameters": {
        "jsCode": "// ================================================\n//  EDIT THIS NODE -- all your settings live here\n// ================================================\n\nvar CLINIC_NAME     = 'Your Clinic Name';\nvar BOOKING_LINK    = 'YOUR_BOOKING_LINK';\nvar SLACK_CHANNEL   = 'YOUR_SLACK_CHANNEL_ID';\nvar LOG_SHEET_ID    = 'YOUR_LOG_SHEET_ID';\nvar LOG_SHEET_NAME  = 'Communications Log';\n\n// ================================================\n//  DO NOT EDIT BELOW THIS LINE\n// ================================================\n\nvar form = $input.first().json;\n\nvar patientName   = form['Full Name'] || '';\nvar patientEmail  = form['Email Address'] || '';\nvar contactReason = form['Reason for Contact'] || '';\nvar lastVisit     = form['When was your last appointment?'] || 'not recorded';\nvar notes         = form['Additional notes (optional)'] || 'none';\n\nreturn [{\n  json: {\n    clinic_name:    CLINIC_NAME,\n    booking_link:   BOOKING_LINK,\n    slack_channel:  SLACK_CHANNEL,\n    log_sheet_id:   LOG_SHEET_ID,\n    log_sheet_name: LOG_SHEET_NAME,\n    patient_name:   patientName,\n    patient_email:  patientEmail,\n    contact_reason: contactReason,\n    last_visit:     lastVisit,\n    notes:          notes,\n    timestamp:      new Date().toISOString()\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "fa1c2eb4-6b84-4b38-b51c-aecfc3267a58",
      "name": "Build Patient Prompt",
      "type": "n8n-nodes-base.code",
      "position": [
        1008,
        240
      ],
      "parameters": {
        "jsCode": "var d = $input.first().json;\n\nvar prompt = 'You are a patient communication assistant for a clinic called ' + d.clinic_name + '. ' +\n  'Read the patient record below and decide the best action to take. ' +\n  'Respond ONLY with a valid JSON object -- no other text, no markdown, no explanation.\\n\\n' +\n  'PATIENT RECORD:\\n' +\n  'Name: ' + d.patient_name + '\\n' +\n  'Email: ' + d.patient_email + '\\n' +\n  'Reason for contact: ' + d.contact_reason + '\\n' +\n  'Last visit: ' + d.last_visit + '\\n' +\n  'Additional notes: ' + d.notes + '\\n\\n' +\n  'BOOKING LINK: ' + d.booking_link + '\\n\\n' +\n  'ACTION GUIDE:\\n' +\n  'send_welcome -- Patient is new or has never visited before\\n' +\n  'rebook_appointment -- Patient missed an appointment or has not visited in over 6 months\\n' +\n  'send_followup -- Patient had a recent visit or has a general question\\n\\n' +\n  'RETURN THIS EXACT JSON STRUCTURE:\\n' +\n  '{\"action\":\"send_welcome\",\"urgency\":\"normal\",\"email_subject\":\"plain text subject, no emojis\",\"email_body\":\"full plain text email body, warm and professional, include the booking link if relevant, no HTML\",\"reason\":\"one sentence explaining why you chose this action\"}\\n\\n' +\n  'urgency must be high or normal. high means the patient needs to be seen urgently.';\n\nreturn [{ json: Object.assign({}, d, { prompt: prompt }) }];"
      },
      "typeVersion": 2
    },
    {
      "id": "d613dbe0-a1a1-4a1f-a0fe-c6a5082bdb22",
      "name": "Analyse Patient Submission",
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "position": [
        1184,
        240
      ],
      "parameters": {
        "text": "={{ $json.prompt }}",
        "promptType": "define"
      },
      "typeVersion": 1.4
    },
    {
      "id": "7b77e7dd-36ce-4be4-8fe8-1995becc3afc",
      "name": "Claude Sonnet",
      "type": "@n8n/n8n-nodes-langchain.lmChatAnthropic",
      "position": [
        1248,
        448
      ],
      "parameters": {
        "model": "claude-sonnet-4-6",
        "options": {
          "temperature": 0.3
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "d3f59d7d-70e9-42d1-a05c-b266e9e5f2fa",
      "name": "Parse Patient Plan",
      "type": "n8n-nodes-base.code",
      "position": [
        1488,
        240
      ],
      "parameters": {
        "jsCode": "var item = $input.first().json;\nvar rawText = item.text || '';\nvar parsed = {};\n\ntry {\n  var match = rawText.match(/\\{[\\s\\S]*\\}/);\n  if (match) parsed = JSON.parse(match[0]);\n} catch (e) {\n  parsed = {\n    action: 'send_followup',\n    urgency: 'normal',\n    email_subject: 'Following up from our clinic',\n    email_body: 'Thank you for being a valued patient. Please contact us if you need to book or change an appointment.',\n    reason: 'AI parsing failed -- fallback message used'\n  };\n}\n\nvar validActions = ['send_welcome', 'rebook_appointment', 'send_followup'];\nif (!validActions.includes(parsed.action)) parsed.action = 'send_followup';\n\nreturn [{ json: Object.assign({}, item, {\n  action:        parsed.action || 'send_followup',\n  urgency:       parsed.urgency || 'normal',\n  email_subject: parsed.email_subject || 'Message from our clinic',\n  email_body:    parsed.email_body || '',\n  reason:        parsed.reason || '',\n  processed_at:  new Date().toISOString()\n}) }];"
      },
      "typeVersion": 2
    },
    {
      "id": "b80943bd-9b53-4f0f-ae65-0caefdbd0330",
      "name": "Route by Action",
      "type": "n8n-nodes-base.switch",
      "position": [
        1728,
        240
      ],
      "parameters": {
        "rules": {
          "values": [
            {
              "outputKey": "Welcome",
              "conditions": {
                "options": {
                  "version": 1,
                  "leftValue": "",
                  "caseSensitive": false,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.action }}",
                    "rightValue": "send_welcome"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "Rebook",
              "conditions": {
                "options": {
                  "version": 1,
                  "leftValue": "",
                  "caseSensitive": false,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.action }}",
                    "rightValue": "rebook_appointment"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "Follow-Up",
              "conditions": {
                "options": {
                  "version": 1,
                  "leftValue": "",
                  "caseSensitive": false,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.action }}",
                    "rightValue": "send_followup"
                  }
                ]
              },
              "renameOutput": true
            }
          ]
        },
        "options": {}
      },
      "typeVersion": 3.2
    },
    {
      "id": "8d6b2360-a3dc-47b6-9018-eb2916f68089",
      "name": "Send Welcome Email",
      "type": "n8n-nodes-base.gmail",
      "position": [
        2128,
        128
      ],
      "parameters": {
        "sendTo": "={{ $json.patient_email }}",
        "message": "={{ $json.email_body }}",
        "options": {},
        "subject": "={{ $json.email_subject }}",
        "emailType": "text"
      },
      "typeVersion": 2.1
    },
    {
      "id": "741b65a2-096e-434b-951c-313622087996",
      "name": "Log Welcome",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        2352,
        128
      ],
      "parameters": {
        "columns": {
          "value": {
            "Action": "={{ $('Parse Patient Plan').item.json.action }}",
            "Reason": "={{ $('Parse Patient Plan').item.json.reason }}",
            "Status": "Welcome Email Sent",
            "Urgency": "={{ $('Parse Patient Plan').item.json.urgency }}",
            "Timestamp": "={{ $('Parse Patient Plan').item.json.processed_at }}",
            "Patient Name": "={{ $('Parse Patient Plan').item.json.patient_name }}",
            "Email Subject": "={{ $('Parse Patient Plan').item.json.email_subject }}",
            "Patient Email": "={{ $('Parse Patient Plan').item.json.patient_email }}"
          },
          "mappingMode": "defineBelow"
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "={{ $('Parse Patient Plan').item.json.log_sheet_name }}"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Parse Patient Plan').item.json.log_sheet_id }}"
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "3ac5329e-d3b5-462d-9a5e-0d1a0eca4e77",
      "name": "Send Rebook Email",
      "type": "n8n-nodes-base.gmail",
      "position": [
        2128,
        272
      ],
      "parameters": {
        "sendTo": "={{ $json.patient_email }}",
        "message": "={{ $json.email_body }}",
        "options": {},
        "subject": "={{ $json.email_subject }}",
        "emailType": "text"
      },
      "typeVersion": 2.1
    },
    {
      "id": "4d68dfb8-d6bd-452a-a8ab-f9662584fe3f",
      "name": "Prepare Slack Message",
      "type": "n8n-nodes-base.code",
      "position": [
        2352,
        272
      ],
      "parameters": {
        "jsCode": "var item = $input.first().json;\nvar msg = 'Re-booking email sent to patient\\n' +\n  'Patient: ' + (item.patient_name || 'unknown') + '\\n' +\n  'Email: ' + (item.patient_email || 'unknown') + '\\n' +\n  'Last visit: ' + (item.last_visit || 'unknown') + '\\n' +\n  'Reason for contact: ' + (item.contact_reason || 'unknown') + '\\n' +\n  'Claude reasoning: ' + (item.reason || 'n/a') + '\\n' +\n  'Please follow up to confirm a new appointment time.';\nreturn [{ json: Object.assign({}, item, { slack_message: msg }) }];"
      },
      "typeVersion": 2
    },
    {
      "id": "7cc063d6-c299-4b81-ba82-3065a35303a1",
      "name": "Notify Clinic Manager",
      "type": "n8n-nodes-base.slack",
      "position": [
        2560,
        272
      ],
      "parameters": {
        "text": "={{ $json.slack_message }}",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $json.slack_channel }}"
        },
        "otherOptions": {}
      },
      "typeVersion": 2.2
    },
    {
      "id": "ac1cbeb5-750a-40c9-9c35-e333adfd5931",
      "name": "Log Rebook",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        2784,
        272
      ],
      "parameters": {
        "columns": {
          "value": {
            "Action": "={{ $('Parse Patient Plan').item.json.action }}",
            "Reason": "={{ $('Parse Patient Plan').item.json.reason }}",
            "Status": "Rebook Email Sent - Slack Notified",
            "Urgency": "={{ $('Parse Patient Plan').item.json.urgency }}",
            "Timestamp": "={{ $('Parse Patient Plan').item.json.processed_at }}",
            "Patient Name": "={{ $('Parse Patient Plan').item.json.patient_name }}",
            "Email Subject": "={{ $('Parse Patient Plan').item.json.email_subject }}",
            "Patient Email": "={{ $('Parse Patient Plan').item.json.patient_email }}"
          },
          "mappingMode": "defineBelow"
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "={{ $('Parse Patient Plan').item.json.log_sheet_name }}"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Parse Patient Plan').item.json.log_sheet_id }}"
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "7d5546c9-6905-4344-8178-892fb8032ce7",
      "name": "Send Follow-Up Email",
      "type": "n8n-nodes-base.gmail",
      "position": [
        2128,
        400
      ],
      "parameters": {
        "sendTo": "={{ $json.patient_email }}",
        "message": "={{ $json.email_body }}",
        "options": {},
        "subject": "={{ $json.email_subject }}",
        "emailType": "text"
      },
      "typeVersion": 2.1
    },
    {
      "id": "78e9836c-ad7e-4a1f-b46d-01eb8ea024a3",
      "name": "Log Follow-Up",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        2352,
        400
      ],
      "parameters": {
        "columns": {
          "value": {
            "Action": "={{ $('Parse Patient Plan').item.json.action }}",
            "Reason": "={{ $('Parse Patient Plan').item.json.reason }}",
            "Status": "Follow-Up Email Sent",
            "Urgency": "={{ $('Parse Patient Plan').item.json.urgency }}",
            "Timestamp": "={{ $('Parse Patient Plan').item.json.processed_at }}",
            "Patient Name": "={{ $('Parse Patient Plan').item.json.patient_name }}",
            "Email Subject": "={{ $('Parse Patient Plan').item.json.email_subject }}",
            "Patient Email": "={{ $('Parse Patient Plan').item.json.patient_email }}"
          },
          "mappingMode": "defineBelow"
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "={{ $('Parse Patient Plan').item.json.log_sheet_name }}"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Parse Patient Plan').item.json.log_sheet_id }}"
        }
      },
      "typeVersion": 4.5
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "executionOrder": "v1"
  },
  "versionId": "35b280ac-c205-4d4c-a551-02c18686485c",
  "connections": {
    "Claude Sonnet": {
      "ai_languageModel": [
        [
          {
            "node": "Analyse Patient Submission",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Route by Action": {
      "main": [
        [
          {
            "node": "Send Welcome Email",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Send Rebook Email",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Send Follow-Up Email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Rebook Email": {
      "main": [
        [
          {
            "node": "Prepare Slack Message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Patient Plan": {
      "main": [
        [
          {
            "node": "Route by Action",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Welcome Email": {
      "main": [
        [
          {
            "node": "Log Welcome",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Patient Intake Form": {
      "main": [
        [
          {
            "node": "Configure Clinic Settings",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Patient Prompt": {
      "main": [
        [
          {
            "node": "Analyse Patient Submission",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Follow-Up Email": {
      "main": [
        [
          {
            "node": "Log Follow-Up",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Notify Clinic Manager": {
      "main": [
        [
          {
            "node": "Log Rebook",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Slack Message": {
      "main": [
        [
          {
            "node": "Notify Clinic Manager",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Configure Clinic Settings": {
      "main": [
        [
          {
            "node": "Build Patient Prompt",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Analyse Patient Submission": {
      "main": [
        [
          {
            "node": "Parse Patient Plan",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}