This workflow follows the Form → HTTP Request 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 →
{
"name": "AI Trial Manager (Gmail \u2192 Gemini \u2192 HITL \u2192 Calendar)",
"nodes": [
{
"parameters": {
"pollTimes": {
"item": [
{
"mode": "everyMinute"
}
]
},
"authentication": "serviceAccount",
"filters": {
"readStatus": "unread"
}
},
"id": "node-gmail-trigger",
"name": "Gmail Trigger \u2014 Poll Inbox",
"type": "n8n-nodes-base.gmailTrigger",
"typeVersion": 1.2,
"position": [
-832,
-192
],
"credentials": {
"googleApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "cfg-app-url",
"name": "app_url",
"value": "https://YOUR_APP_DOMAIN",
"type": "string"
},
{
"id": "cfg-secret",
"name": "webhook_secret",
"value": "YOUR_WEBHOOK_SECRET",
"type": "string"
},
{
"id": "cfg-admin-email",
"name": "admin_email",
"value": "YOUR_ADMIN_EMAIL",
"type": "string"
},
{
"id": "cfg-telegram-admin-chat",
"name": "telegram_admin_chat_id",
"value": "YOUR_ADMIN_TELEGRAM_CHAT_ID",
"type": "string"
},
{
"id": "cfg-telegram-group-chat",
"name": "telegram_group_chat_id",
"value": "YOUR_TELEGRAM_GROUP_CHAT_ID",
"type": "string"
},
{
"id": "cfg-bot-token",
"name": "telegram_bot_token",
"value": "YOUR_TELEGRAM_BOT_TOKEN",
"type": "string"
},
{
"id": "cfg-gemini-key",
"name": "gemini_api_key",
"value": "YOUR_GEMINI_API_KEY",
"type": "string"
},
{
"id": "cfg-coaches-topic",
"name": "coaches_topic_id",
"value": "YOUR_COACHES_TOPIC_ID",
"type": "string"
},
{
"id": "cfg-tournament-topic",
"name": "tournament_topic_id",
"value": "YOUR_TOURNAMENT_TOPIC_ID",
"type": "string"
}
]
},
"options": {}
},
"id": "node-config",
"name": "Config",
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
-608,
-192
]
},
{
"parameters": {
"authentication": "serviceAccount",
"sendTo": "={{ $json.from.value[0].address }}",
"subject": "RE: {{ $json.subject }}",
"message": "Thank you for contacting us!\n\nWe have received your message and our team will review it shortly. You will receive a follow-up within 24 hours.\n\nBest regards,\n[YOUR ORGANIZATION NAME]",
"options": {}
},
"id": "node-autoreply",
"name": "Auto-Reply \u2014 Acknowledge",
"type": "n8n-nodes-base.gmail",
"typeVersion": 2.1,
"position": [
-400,
-352
],
"credentials": {
"googleApi": {
"name": "<your credential>"
}
},
"continueOnFail": true
},
{
"parameters": {
"method": "POST",
"url": "=https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Content-Type",
"value": "application/json"
},
{
"name": "x-goog-api-key",
"value": "={{ $('Config').item.json.gemini_api_key }}"
}
]
},
"sendBody": true,
"contentType": "raw",
"rawContentType": "application/json",
"body": "={{ JSON.stringify({ contents: [{ parts: [{ text: 'Analyze the following email and extract structured data.\\n\\nEmail Subject: ' + $('Gmail Trigger \u2014 Poll Inbox').item.json.subject + '\\nEmail From: ' + $('Gmail Trigger \u2014 Poll Inbox').item.json.from.value[0].address + '\\nEmail Body:\\n' + ($('Gmail Trigger \u2014 Poll Inbox').item.json.text || $('Gmail Trigger \u2014 Poll Inbox').item.json.html || '') + '\\n\\nExtract the following fields as JSON:\\n- player_name: The name of the player (if mentioned)\\n- age_group: The age group \u2014 infer from age or date of birth if possible\\n- intent: One of \"trial\", \"fixture\", \"general_inquiry\", \"registration\", \"complaint\"\\n- parent_name: The parent/guardian name (if mentioned)\\n- parent_phone: Phone number (if mentioned)\\n- parent_email: Email address (use the From address if no other is specified)\\n- summary: A 1-2 sentence summary of the request\\n- urgency: \"high\", \"medium\", or \"low\"\\n\\nReturn ONLY valid JSON, no markdown fences.' }] }], generationConfig: { temperature: 0.1, maxOutputTokens: 500 } }) }}",
"options": {
"response": {
"response": {
"neverError": true
}
}
}
},
"id": "node-gemini",
"name": "Gemini \u2014 Extract Info",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
-400,
-32
]
},
{
"parameters": {
"jsCode": "const response = $('Gemini \u2014 Extract Info').item.json;\n\nlet raw = '';\ntry { raw = response.candidates[0].content.parts[0].text || ''; } catch (e) { raw = ''; }\n\nlet parsed;\ntry {\n const cleaned = raw.replace(/```json\\n?/g, '').replace(/```\\n?/g, '').trim();\n parsed = JSON.parse(cleaned);\n} catch (e) {\n parsed = {\n player_name: 'Unknown',\n age_group: 'Unknown',\n intent: 'general_inquiry',\n parent_name: 'Unknown',\n parent_email: $('Gmail Trigger \u2014 Poll Inbox').item.json.from.value[0].address,\n summary: 'Could not parse email automatically',\n urgency: 'medium'\n };\n}\n\nconst originalEmail = $('Gmail Trigger \u2014 Poll Inbox').item.json;\n\nreturn {\n json: {\n ...parsed,\n original_subject: originalEmail.subject,\n original_from: originalEmail.from.value[0].address,\n original_date: originalEmail.date,\n gmail_message_id: originalEmail.id\n }\n};"
},
"id": "node-parse-ai",
"name": "Parse AI Response",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
-176,
-32
]
},
{
"parameters": {
"url": "={{ $('Config').item.json.app_url }}/api/calendar/availability",
"sendQuery": true,
"queryParameters": {
"parameters": [
{
"name": "start",
"value": "={{ $now.plus(2, 'days').startOf('day').plus(9, 'hours').toISO() }}"
},
{
"name": "end",
"value": "={{ $now.plus(2, 'days').startOf('day').plus(11, 'hours').toISO() }}"
}
]
},
"options": {
"response": {
"response": {
"neverError": true
}
}
}
},
"id": "node-cal-check",
"name": "Check Calendar Availability",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
48,
-32
],
"continueOnFail": true
},
{
"parameters": {
"jsCode": "const ai = $('Parse AI Response').item.json;\nconst cal = $('Check Calendar Availability').item.json;\nconst config = $('Config').item.json;\n\nconst available = cal.available !== false;\nconst conflicts = cal.conflicts || [];\n\nlet calendarNote = available\n ? '\u2705 Next available slot: Day after tomorrow, 9:00-11:00 AM'\n : '\u26a0\ufe0f Calendar conflict: ' + conflicts.map(c => c.summary).join(', ');\n\nconst reviewMessage = [\n '\ud83d\udce9 <b>New Trial/Inquiry Request</b>',\n '',\n `<b>Intent:</b> ${ai.intent}`,\n `<b>Player:</b> ${ai.player_name || 'Not specified'}`,\n `<b>Age Group:</b> ${ai.age_group || 'Not specified'}`,\n `<b>Parent:</b> ${ai.parent_name || 'Not specified'}`,\n `<b>Email:</b> ${ai.original_from}`,\n `<b>Phone:</b> ${ai.parent_phone || 'Not specified'}`,\n '',\n `<b>Summary:</b> ${ai.summary}`,\n `<b>Urgency:</b> ${ai.urgency}`,\n '',\n `<b>Calendar:</b> ${calendarNote}`,\n '',\n '\ud83d\udc47 <b>Reply with:</b>',\n '<code>/approve</code> \u2014 Create calendar event + send confirmation',\n '<code>/reject</code> \u2014 Send polite decline email'\n].join('\\n');\n\nreturn {\n json: {\n reviewMessage,\n aiData: ai,\n calendarAvailable: available,\n calendarNote\n }\n};"
},
"id": "node-build-review",
"name": "Build Review Message",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
272,
-32
]
},
{
"parameters": {
"method": "POST",
"url": "=https://api.telegram.org/bot{{ $('Config').item.json.telegram_bot_token }}/sendMessage",
"sendBody": true,
"contentType": "raw",
"rawContentType": "application/json",
"body": "={{ JSON.stringify({ chat_id: $('Config').item.json.telegram_admin_chat_id, text: $json.reviewMessage, parse_mode: 'HTML' }) }}",
"options": {
"response": {
"response": {
"neverError": true
}
}
}
},
"id": "node-send-hitl",
"name": "Send to Admin \u2014 Telegram HITL",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
496,
-32
]
},
{
"parameters": {},
"id": "node-hitl-wait",
"name": "HITL \u2014 Wait for Decision",
"type": "n8n-nodes-base.form",
"typeVersion": 2.2,
"position": [
720,
-32
]
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": false
},
"conditions": [
{
"id": "check-approve",
"leftValue": "={{ $json.Decision }}",
"rightValue": "approve",
"operator": {
"type": "string",
"operation": "equals"
}
}
]
},
"options": {}
},
"id": "node-approved",
"name": "Approved?",
"type": "n8n-nodes-base.if",
"typeVersion": 2.2,
"position": [
928,
-32
]
},
{
"parameters": {
"method": "POST",
"url": "={{ $('Config').item.json.app_url }}/api/calendar",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Content-Type",
"value": "application/json"
}
]
},
"sendBody": true,
"contentType": "raw",
"rawContentType": "application/json",
"body": "={{ JSON.stringify({ summary: 'Trial \u2014 ' + ($('Build Review Message').item.json.aiData.player_name || 'New Player') + ' (' + ($('Build Review Message').item.json.aiData.age_group || 'TBD') + ')', description: 'Trial request from ' + $('Build Review Message').item.json.aiData.original_from, location: 'Training Ground', startTime: ($json['Preferred Date'] || $now.plus(2, 'days').toISODate()) + 'T' + ($json['Preferred Time'] || '09:00') + ':00.000+04:00', endTime: ($json['Preferred Date'] || $now.plus(2, 'days').toISODate()) + 'T' + ($json['Preferred Time'] ? String(Number($json['Preferred Time'].split(':')[0]) + 2).padStart(2, '0') + ':00' : '11:00') + ':00.000+04:00', checkAvailability: true }) }}",
"options": {
"response": {
"response": {
"neverError": true
}
}
}
},
"id": "node-create-cal",
"name": "Create Calendar Event",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1152,
-160
],
"continueOnFail": true
},
{
"parameters": {
"authentication": "serviceAccount",
"sendTo": "={{ $('Build Review Message').item.json.aiData.original_from }}",
"subject": "[YOUR ORG] \u2014 Your Trial Session is Confirmed!",
"message": "=Dear {{ $('Build Review Message').item.json.aiData.parent_name || 'Parent/Guardian' }},\n\nGreat news! We're happy to confirm a trial session for {{ $('Build Review Message').item.json.aiData.player_name || 'your child' }}.\n\n\ud83d\udcc5 Date: {{ $('HITL \u2014 Wait for Decision').item.json['Preferred Date'] || 'To be confirmed' }}\n\u23f0 Time: {{ $('HITL \u2014 Wait for Decision').item.json['Preferred Time'] || '9:00 AM' }}\n\ud83d\udccd Location: Training Ground\n\nPlease bring comfortable sportswear and a water bottle.\n\nBest regards,\n[YOUR ORGANIZATION NAME]",
"options": {}
},
"id": "node-confirm-email",
"name": "Send Confirmation Email",
"type": "n8n-nodes-base.gmail",
"typeVersion": 2.1,
"position": [
1376,
-160
],
"credentials": {
"googleApi": {
"name": "<your credential>"
}
},
"continueOnFail": true
},
{
"parameters": {
"authentication": "serviceAccount",
"sendTo": "={{ $('Build Review Message').item.json.aiData.original_from }}",
"subject": "RE: {{ $('Build Review Message').item.json.aiData.original_subject }}",
"message": "=Dear {{ $('Build Review Message').item.json.aiData.parent_name || 'Parent/Guardian' }},\n\nThank you for your interest.\n\nUnfortunately, we are unable to accommodate your request at this time.\n\nPlease don't hesitate to reach out again in the future.\n\nBest regards,\n[YOUR ORGANIZATION NAME]",
"options": {}
},
"id": "node-reject-email",
"name": "Send Rejection Email",
"type": "n8n-nodes-base.gmail",
"typeVersion": 2.1,
"position": [
1152,
96
],
"credentials": {
"googleApi": {
"name": "<your credential>"
}
},
"continueOnFail": true
},
{
"parameters": {
"method": "POST",
"url": "=https://api.telegram.org/bot{{ $('Config').item.json.telegram_bot_token }}/sendMessage",
"sendBody": true,
"contentType": "raw",
"rawContentType": "application/json",
"body": "={{ JSON.stringify({ chat_id: $('Config').item.json.telegram_admin_chat_id, text: '\u2705 Trial APPROVED for ' + ($('Build Review Message').item.json.aiData.player_name || 'Unknown') + '. Calendar event created. Confirmation email sent.', parse_mode: 'HTML' }) }}",
"options": {}
},
"id": "node-notify-approved",
"name": "Notify Admin \u2014 Approved",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1600,
-160
],
"continueOnFail": true
},
{
"parameters": {
"method": "POST",
"url": "=https://api.telegram.org/bot{{ $('Config').item.json.telegram_bot_token }}/sendMessage",
"sendBody": true,
"contentType": "raw",
"rawContentType": "application/json",
"body": "={{ JSON.stringify({ chat_id: $('Config').item.json.telegram_admin_chat_id, text: '\u274c Trial REJECTED for ' + ($('Build Review Message').item.json.aiData.player_name || 'Unknown') + '. Decline email sent.', parse_mode: 'HTML' }) }}",
"options": {}
},
"id": "node-notify-rejected",
"name": "Notify Admin \u2014 Rejected",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1376,
96
],
"continueOnFail": true
}
],
"connections": {
"Gmail Trigger \u2014 Poll Inbox": {
"main": [
[
{
"node": "Config",
"type": "main",
"index": 0
}
]
]
},
"Config": {
"main": [
[
{
"node": "Auto-Reply \u2014 Acknowledge",
"type": "main",
"index": 0
},
{
"node": "Gemini \u2014 Extract Info",
"type": "main",
"index": 0
}
]
]
},
"Gemini \u2014 Extract Info": {
"main": [
[
{
"node": "Parse AI Response",
"type": "main",
"index": 0
}
]
]
},
"Parse AI Response": {
"main": [
[
{
"node": "Check Calendar Availability",
"type": "main",
"index": 0
}
]
]
},
"Check Calendar Availability": {
"main": [
[
{
"node": "Build Review Message",
"type": "main",
"index": 0
}
]
]
},
"Build Review Message": {
"main": [
[
{
"node": "Send to Admin \u2014 Telegram HITL",
"type": "main",
"index": 0
}
]
]
},
"Approved?": {
"main": [
[
{
"node": "Create Calendar Event",
"type": "main",
"index": 0
}
],
[
{
"node": "Send Rejection Email",
"type": "main",
"index": 0
}
]
]
},
"Create Calendar Event": {
"main": [
[
{
"node": "Send Confirmation Email",
"type": "main",
"index": 0
}
]
]
},
"Send Confirmation Email": {
"main": [
[
{
"node": "Notify Admin \u2014 Approved",
"type": "main",
"index": 0
}
]
]
},
"Send Rejection Email": {
"main": [
[
{
"node": "Notify Admin \u2014 Rejected",
"type": "main",
"index": 0
}
]
]
}
},
"active": false,
"settings": {
"executionOrder": "v1"
},
"tags": [
{
"name": "AI"
},
{
"name": "Email"
},
{
"name": "HITL"
},
{
"name": "Telegram"
}
]
}
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.
googleApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
How this works
This workflow streamlines managing AI tool trials by automatically processing incoming Gmail requests, extracting key details with Google's Gemini AI, and scheduling suitable times in your calendar after human review. It's ideal for product managers or support teams handling demo or trial sign-ups, saving hours of manual coordination and ensuring prompt responses. The pivotal step involves Gemini analysing the email to pull out trial specifics like user needs and preferred dates, which then feeds into a Telegram alert for quick human approval before booking the slot.
Use this when you receive a steady stream of trial inquiries via email and need to balance automation with human oversight for scheduling accuracy, particularly in fast-paced tech environments. Avoid it for low-volume requests where simple manual replies suffice, or if your team lacks Telegram for the approval step. Common variations include swapping Gemini for another AI API or integrating Slack instead of Telegram for the human-in-the-loop review.
About this workflow
AI Trial Manager (Gmail → Gemini → HITL → Calendar). Uses gmailTrigger, gmail, httpRequest, form. Event-driven trigger; 15 nodes.
Source: https://github.com/hasancoded/n8n-workflow-templates/blob/main/ai-trial-manager.json — 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.
AICARE Email Blast System. Uses googleDrive, httpRequest, googleSheets, gmail. Event-driven trigger; 39 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
ResultAnalyser. Uses gmailTrigger, executeCommand, httpRequest, gmail. Event-driven trigger; 23 nodes.
An automated n8n workflow that monitors your Gmail inbox, classifies job application emails using a local AI (Ollama), and logs every application — with company, role, and status — to a Google Sheet i