This workflow corresponds to n8n.io template #5879 — we link there as the canonical source.
This workflow follows the Form Trigger → Gmail 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 →
{
"id": "Mtw9IrtjflcYG15X",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "Automated Appointment Letter : template, email, Human-In-The-Loop approval",
"tags": [],
"nodes": [
{
"id": "a780c025-f915-4707-a754-432f57574201",
"name": "On form submission",
"type": "n8n-nodes-base.formTrigger",
"position": [
-816,
-176
],
"parameters": {
"options": {},
"formTitle": "Generate Appointment Letter",
"formFields": {
"values": [
{
"fieldLabel": "Candidate Name"
},
{
"fieldLabel": "Position Name"
},
{
"fieldLabel": "Fixed CTC"
},
{
"fieldLabel": "Joining Date"
},
{
"fieldLabel": "To be signed by Date"
},
{
"fieldLabel": "Candidate email"
}
]
}
},
"typeVersion": 2.2
},
{
"id": "2335a0b2-1feb-41ca-95ec-b1433f0c0c7b",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-896,
-368
],
"parameters": {
"width": 224,
"height": 432,
"content": "Use the form fields to update the Appointment letter template and create a candidate specific appointment letter in PDF format on the Goolge drive"
},
"typeVersion": 1
},
{
"id": "51bfaaee-9198-4c5d-8a8a-0aab475ba5a5",
"name": "Create a candidate copy of the appointment letter template",
"type": "n8n-nodes-base.googleDrive",
"position": [
-608,
-176
],
"parameters": {
"name": "=Appointment Letter - {{ $json['Candidate Name'] }}",
"fileId": {
"__rl": true,
"mode": "list",
"value": "1B-AEAw4Uxg313lXW_HsoviNSE3UiRmebq7hICdbQPGo",
"cachedResultUrl": "https://docs.google.com/document/d/1B-AEAw4Uxg313lXW_HsoviNSE3UiRmebq7hICdbQPGo/edit?usp=drivesdk",
"cachedResultName": "Appointment Letter"
},
"options": {
"description": "",
"copyRequiresWriterPermission": false
},
"operation": "copy"
},
"credentials": {
"googleDriveOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 3
},
{
"id": "44743441-aa57-4c5e-a74b-7890b547e1d0",
"name": "Update the candidate appointment letter with offer details",
"type": "n8n-nodes-base.googleDocs",
"position": [
-336,
-176
],
"parameters": {
"actionsUi": {
"actionFields": [
{
"text": "[Candidate Name]",
"action": "replaceAll",
"replaceText": "={{ $('On form submission').item.json['Candidate Name'] }}"
},
{
"text": "[Position Name]",
"action": "replaceAll",
"replaceText": "={{ $('On form submission').item.json['Position Name'] }}"
},
{
"text": "[Fixed CTC]",
"action": "replaceAll",
"replaceText": "={{ $('On form submission').item.json['Fixed CTC'] }}"
},
{
"text": "[Joining Date]",
"action": "replaceAll",
"replaceText": "={{ $('On form submission').item.json['Joining Date'] }}"
},
{
"text": "[To be signed by Date]",
"action": "replaceAll",
"replaceText": "={{ $('On form submission').item.json['To be signed by Date'] }}"
},
{
"text": "[Date]",
"action": "replaceAll",
"replaceText": "={{ $now.toFormat('MM-dd-yyyy') }}"
}
]
},
"operation": "update",
"documentURL": "={{ $json.id }}"
},
"credentials": {
"googleDocsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 2
},
{
"id": "395f9d2d-9422-4e37-885c-ced8b5eabc27",
"name": "Download the appointment letter as a PDF",
"type": "n8n-nodes-base.googleDrive",
"position": [
-96,
-176
],
"parameters": {
"fileId": {
"__rl": true,
"mode": "id",
"value": "={{ $json.documentId }}"
},
"options": {
"binaryPropertyName": "data",
"googleFileConversion": {
"conversion": {
"docsToFormat": "application/pdf"
}
}
},
"operation": "download"
},
"credentials": {
"googleDriveOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 3
},
{
"id": "faf3bb5d-7cd7-4223-ac14-c0ad2e1e2d1b",
"name": "Upload the PDF to Google drive",
"type": "n8n-nodes-base.googleDrive",
"position": [
128,
-176
],
"parameters": {
"name": "={{ $('Create a candidate copy of the appointment letter template').item.json.name }}",
"driveId": {
"__rl": true,
"mode": "list",
"value": "My Drive",
"cachedResultUrl": "https://drive.google.com/drive/my-drive",
"cachedResultName": "My Drive"
},
"options": {},
"folderId": {
"__rl": true,
"mode": "list",
"value": "1NFN9rLttv6eF8vo2qWBCSzXgR4A3cjGr",
"cachedResultUrl": "https://drive.google.com/drive/folders/1NFN9rLttv6eF8vo2qWBCSzXgR4A3cjGr",
"cachedResultName": "Appointment Letter"
}
},
"credentials": {
"googleDriveOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 3
},
{
"id": "412d294d-e441-490c-9341-6343a52dad30",
"name": "Send message and wait for response",
"type": "n8n-nodes-base.gmail",
"position": [
368,
-176
],
"parameters": {
"sendTo": "user@example.com",
"message": "=Hi HR,\n\nPlease review and approve the appointment letter for {{ $('On form submission').item.json['Candidate Name'] }}\n\nThank You.\n ",
"options": {},
"subject": "=Approval required - {{ $json.name }}",
"operation": "sendAndWait",
"approvalOptions": {
"values": {
"approvalType": "double"
}
}
},
"credentials": {
"gmailOAuth2": {
"name": "<your credential>"
}
},
"typeVersion": 2.1
},
{
"id": "8e080cbf-ed7d-4812-929b-8091557fd976",
"name": "If",
"type": "n8n-nodes-base.if",
"position": [
624,
-176
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "d89063c7-bff6-48be-bd1d-fdce241bde75",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
},
"leftValue": "={{ $json.data.approved }}",
"rightValue": ""
}
]
}
},
"typeVersion": 2.2
},
{
"id": "7641c843-0176-4dc3-a9a9-58cc1dea6d2c",
"name": "Download file",
"type": "n8n-nodes-base.googleDrive",
"position": [
800,
-336
],
"parameters": {
"fileId": {
"__rl": true,
"mode": "id",
"value": "={{ $('Upload the PDF to Google drive').item.json.id }}"
},
"options": {
"googleFileConversion": {}
},
"operation": "download"
},
"credentials": {
"googleDriveOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 3
},
{
"id": "135e5e92-69d3-4226-a1ca-85c62c2d6833",
"name": "Send a message",
"type": "n8n-nodes-base.gmail",
"position": [
976,
-336
],
"parameters": {
"sendTo": "={{ $('On form submission').item.json['Candidate email'] }}",
"message": "=Congratulations {{ $('On form submission').item.json['Candidate Name'] }}\n\nPlease email before {{ $('On form submission').item.json['To be signed by Date'] }}",
"options": {
"attachmentsUi": {
"attachmentsBinary": [
{}
]
}
},
"subject": "Appointment Letter"
},
"credentials": {
"gmailOAuth2": {
"name": "<your credential>"
}
},
"typeVersion": 2.1
},
{
"id": "700b3e39-8143-4d7d-9048-d3a56fc71fd6",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-656,
-368
],
"parameters": {
"width": 928,
"height": 432,
"content": "Create a candidate specific version of the appointment letter and create a PDF version of it. Store this on the Google Drive"
},
"typeVersion": 1
},
{
"id": "6dce69ae-fff6-463a-80f1-e7480a20597b",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
288,
-368
],
"parameters": {
"width": 288,
"height": 432,
"content": "Human-In-The-Loop step - Send an email to the HR manager requesting to review the appointment letter and \"Approve\"or \"Reject\""
},
"typeVersion": 1
},
{
"id": "fec624e5-c0d1-4533-b705-397eb9304a5c",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
768,
-432
],
"parameters": {
"width": 384,
"height": 256,
"content": "If the HR manager approves, send an email to the candidate with the appointment letter as a PDF attachment"
},
"typeVersion": 1
}
],
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "fe72a03c-0b86-4815-a06b-172a243ce11c",
"connections": {
"If": {
"main": [
[
{
"node": "Download file",
"type": "main",
"index": 0
}
]
]
},
"Download file": {
"main": [
[
{
"node": "Send a message",
"type": "main",
"index": 0
}
]
]
},
"On form submission": {
"main": [
[
{
"node": "Create a candidate copy of the appointment letter template",
"type": "main",
"index": 0
}
]
]
},
"Upload the PDF to Google drive": {
"main": [
[
{
"node": "Send message and wait for response",
"type": "main",
"index": 0
}
]
]
},
"Send message and wait for response": {
"main": [
[
{
"node": "If",
"type": "main",
"index": 0
}
]
]
},
"Download the appointment letter as a PDF": {
"main": [
[
{
"node": "Upload the PDF to Google drive",
"type": "main",
"index": 0
}
]
]
},
"Create a candidate copy of the appointment letter template": {
"main": [
[
{
"node": "Update the candidate appointment letter with offer details",
"type": "main",
"index": 0
}
]
]
},
"Update the candidate appointment letter with offer details": {
"main": [
[
{
"node": "Download the appointment letter as a PDF",
"type": "main",
"index": 0
}
]
]
}
}
}
Credentials you'll need
Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.
gmailOAuth2googleDocsOAuth2ApigoogleDriveOAuth2Api
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This n8n template demonstrates automating an appointment letter creation process using a template and then having the HR approve before emailing the appointment letter to the candidate.
Source: https://n8n.io/workflows/5879/ — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
Gerador de Contratos. Uses formTrigger, googleDocs, googleDrive, gmail. Event-driven trigger; 9 nodes.
Gerador de Contratos Chácara - Limpo. Uses formTrigger, googleDrive, gmail, googleDocs. Event-driven trigger; 7 nodes.
🎥 Analyze YouTube Video for Summaries, Transcripts & Content + Google Gemini AI. Uses stickyNote, httpRequest, googleDrive, gmail. Event-driven trigger; 33 nodes.
Client Form → Draft → Approve → Sign → Deliver, fully automated
This workflow automates the full offer letter lifecycle, from generation to final candidate response tracking. When a new row with a Pending status is added to Google Sheets, it creates a personalized