Email Answer Approval

Telegram Bot Approval

This workflow is designed to streamline the process of responding to incoming messages. The sequence begins with a Gmail trigger that activates an AI-powered text generator to draft a potential reply. Before any response is finalized, the system incorporates a human-in-the-loop step where an approval task is sent via a messaging notification. Depending on the user's feedback, a logic switch either proceeds to format the final data or routes the content back to the AI model for further revisions. This architecture ensures that artificial intelligence remains supervised by a person to maintain accuracy and quality control. Overall, the diagram depicts a sophisticated n8n automation that balances efficiency with manual oversight.

Human in the Loop

Click on the workflows to Download for FREE !!

// This loop ensures the code runs for every item in the current execution

return items.map(item => {

// 1. Get the raw data (e.g., "5051, true")

const rawExecutionData = item.json.execution_id || "";

const feedbackText = item.json.feedback || "";

// 2. Split by comma and take the first part only

const parts = rawExecutionData.split(',').map(p => p.trim());

// 3. Return the structured object without the "approval" key

return {

json: {

id: "",

feedback: feedbackText,

execution_id: parts[0] || "" // This captures just the number (e.g., "5051")

}

};

});

Extract feedback Data {}

JS Codes {}

// This loop ensures the code runs for every item in the current execution

return items.map(item => {

// 1. Get the data from the previous "Approval data" node

// We use item.json.execution_id to match your Set node exactly

const rawExecutionData = item.json.execution_id || "";

const feedbackText = item.json.feedback || "";

// 2. Split "5051, true" by the comma

const parts = rawExecutionData.split(',').map(p => p.trim());

// 3. Return the structured object n8n needs

return {

json: {

id: "",

approval: parts[1] || "", // This will be "true" or "false"

feedback: feedbackText, // This will be your Telegram message text

execution_id: parts[0] || "" // This will be "5051"

}

};

});

Extract Approval Data {}

// Add a "Code" node after your EMAIL ANSWER GENERATOR

const rawText = $input.item.json.text;

// 1. Find the JSON part inside the markdown backticks

const jsonMatch = rawText.match(/```json\n([\s\S]*?)\n```/);

if (jsonMatch && jsonMatch[1]) {

// 2. Parse the extracted string into a real JSON object

const cleanObject = JSON.parse(jsonMatch[1]);

// 3. Return the object so n8n can use 'subject' and 'body' as separate fields

return cleanObject;

}

// Fallback if no JSON found

return {

error: "Could not find JSON in response",

original: rawText

};

Output Parser { } Option 1

// Add a "Code" node after your EMAIL ANSWER GENERATOR

const rawText = $input.item.json.text;

// 1. Find the JSON part inside the markdown backticks

const jsonMatch = rawText.match(/```json\n([\s\S]*?)\n```/);

if (jsonMatch && jsonMatch[1]) {

// 2. Parse the extracted string into a real JSON object

const cleanObject = JSON.parse(jsonMatch[1]);

// --- NEW STEP: Remove newlines from all string values ---

for (const key in cleanObject) {

if (typeof cleanObject[key] === 'string') {

// Replaces all newlines with a space (prevents words from sticking together)

// Use .replace(/\n/g, "") if you want them gone entirely with no space

cleanObject[key] = cleanObject[key].replace(/\n/g, " ").trim();

}

}

// --------------------------------------------------------

// 3. Return the object so n8n can use 'subject' and 'body' as separate fields

return cleanObject;

}

// Fallback if no JSON found

return {

error: "Could not find JSON in response",

original: rawText

};

JSON Cleaner {}

Output Parser {} Option 2

const rawText = $input.item.json.text;

let parsed;

const start = rawText.indexOf('```');

const end = rawText.lastIndexOf('```');

if (start !== -1 && end !== -1 && start !== end) {

let jsonString = rawText.substring(start + 3, end).trim();

if (jsonString.startsWith('json')) {

jsonString = jsonString.substring(4).trim();

}

parsed = JSON.parse(jsonString);

} else {

const jsonStart = rawText.indexOf('{');

const jsonEnd = rawText.lastIndexOf('}');

if (jsonStart !== -1 && jsonEnd !== -1) {

parsed = JSON.parse(rawText.substring(jsonStart, jsonEnd + 1));

} else {

return {

error: "Could not find JSON in response",

original: rawText

};

}

}

return {

subject: parsed.subject || parsed.Subject || "",

body: parsed.body || parsed.Body || parsed.email_body || parsed.Message || parsed.message || ""

};

Output Parser { } Option 3

const rawText = $input.item.json.text;

let parsed;

const start = rawText.indexOf('```');

const end = rawText.lastIndexOf('```');

if (start !== -1 && end !== -1 && start !== end) {

let jsonString = rawText.substring(start + 3, end).trim();

if (jsonString.startsWith('json')) {

jsonString = jsonString.substring(4).trim();

}

parsed = JSON.parse(jsonString);

} else {

const jsonStart = rawText.indexOf('{');

const jsonEnd = rawText.lastIndexOf('}');

if (jsonStart !== -1 && jsonEnd !== -1) {

jsonSubstring = rawText.substring(jsonStart, jsonEnd + 1).trim();

jsonSubstring = jsonSubstring.replace(/[\n\r\t]/g, '').replace(/\\/g, '\\\\'); // Clean control characters and escape backslashes

parsed = JSON.parse(jsonSubstring);

} else {

return {

error: "Could not find JSON in response",

original: rawText

};

}

}

return {

subject: parsed.subject || parsed.Subject || "",

body: parsed.body || parsed.Body || parsed.email_body || parsed.Message || parsed.message || ""

};