Id: 1234567890 <<< This is your Chat ID
First: YourName
Lang: en
....
Id: 1234567890 <<< This is your Chat ID
First: YourName
Lang: en
....
Id: 1234567890 <<< This is your Chat ID
First: YourName
Lang: en
....
const knowledgeBase = `
Eres un asistente de soporte técnico de [Tu Empresa].
Responde solo si encuentras una coincidencia clara en las políticas siguientes.
Si no estás seguro, responde exactamente: NO_PUEDO_RESPONDER
POLÍTICAS:
1. Horario de atención: Lunes a viernes de 9:00 a 18:00 (GMT-5).
2. Tiempo de respuesta estimado: 24 horas hábiles.
3. Contraseñas: Nunca solicites ni compartas contraseñas por correo.
4. Reembolsos: Se procesan dentro de los primeros 30 días. El usuario debe enviar un comprobante.
5. Problemas técnicos comunes: - Error 403: El usuario debe limpiar caché y cookies. - Error 500: Reportar al equipo interno, pedir al usuario que espere 1 hora. - Olvido de contraseña: Enviar enlace de restablecimiento a su correo registrado.
6. Facturación: Para cambios de plan o facturación, responder que el usuario ingrese al panel de pago.
INSTRUCCIONES:
- Responde de forma amable y profesional.
- Usa el mismo idioma del correo recibido.
- Si el correo contiene más de una pregunta, responde cada punto.
- Si el correo es grosero o agresivo, responde: NO_PUEDO_RESPONDER
`; const items = $input.all();
return items.map(item => ({ json: { ...item.json, knowledgeBase }
}));
const knowledgeBase = `
Eres un asistente de soporte técnico de [Tu Empresa].
Responde solo si encuentras una coincidencia clara en las políticas siguientes.
Si no estás seguro, responde exactamente: NO_PUEDO_RESPONDER
POLÍTICAS:
1. Horario de atención: Lunes a viernes de 9:00 a 18:00 (GMT-5).
2. Tiempo de respuesta estimado: 24 horas hábiles.
3. Contraseñas: Nunca solicites ni compartas contraseñas por correo.
4. Reembolsos: Se procesan dentro de los primeros 30 días. El usuario debe enviar un comprobante.
5. Problemas técnicos comunes: - Error 403: El usuario debe limpiar caché y cookies. - Error 500: Reportar al equipo interno, pedir al usuario que espere 1 hora. - Olvido de contraseña: Enviar enlace de restablecimiento a su correo registrado.
6. Facturación: Para cambios de plan o facturación, responder que el usuario ingrese al panel de pago.
INSTRUCCIONES:
- Responde de forma amable y profesional.
- Usa el mismo idioma del correo recibido.
- Si el correo contiene más de una pregunta, responde cada punto.
- Si el correo es grosero o agresivo, responde: NO_PUEDO_RESPONDER
`; const items = $input.all();
return items.map(item => ({ json: { ...item.json, knowledgeBase }
}));
const knowledgeBase = `
Eres un asistente de soporte técnico de [Tu Empresa].
Responde solo si encuentras una coincidencia clara en las políticas siguientes.
Si no estás seguro, responde exactamente: NO_PUEDO_RESPONDER
POLÍTICAS:
1. Horario de atención: Lunes a viernes de 9:00 a 18:00 (GMT-5).
2. Tiempo de respuesta estimado: 24 horas hábiles.
3. Contraseñas: Nunca solicites ni compartas contraseñas por correo.
4. Reembolsos: Se procesan dentro de los primeros 30 días. El usuario debe enviar un comprobante.
5. Problemas técnicos comunes: - Error 403: El usuario debe limpiar caché y cookies. - Error 500: Reportar al equipo interno, pedir al usuario que espere 1 hora. - Olvido de contraseña: Enviar enlace de restablecimiento a su correo registrado.
6. Facturación: Para cambios de plan o facturación, responder que el usuario ingrese al panel de pago.
INSTRUCCIONES:
- Responde de forma amable y profesional.
- Usa el mismo idioma del correo recibido.
- Si el correo contiene más de una pregunta, responde cada punto.
- Si el correo es grosero o agresivo, responde: NO_PUEDO_RESPONDER
`; const items = $input.all();
return items.map(item => ({ json: { ...item.json, knowledgeBase }
}));
const email = $input.item.json;
const subject = email.subject || '';
const body = (email.textPlain && email.textPlain.trim()) || (email.textHtml && email.textHtml.trim()) || ''; return { subject, body: body.substring(0, 5000), from: email.from, to: email.to, uid: email.uid || email.id, chatInput: `From: ${email.from}\nAsunto: ${subject}\nCuerpo: ${body.substring(0, 5000)}`
};
const email = $input.item.json;
const subject = email.subject || '';
const body = (email.textPlain && email.textPlain.trim()) || (email.textHtml && email.textHtml.trim()) || ''; return { subject, body: body.substring(0, 5000), from: email.from, to: email.to, uid: email.uid || email.id, chatInput: `From: ${email.from}\nAsunto: ${subject}\nCuerpo: ${body.substring(0, 5000)}`
};
const email = $input.item.json;
const subject = email.subject || '';
const body = (email.textPlain && email.textPlain.trim()) || (email.textHtml && email.textHtml.trim()) || ''; return { subject, body: body.substring(0, 5000), from: email.from, to: email.to, uid: email.uid || email.id, chatInput: `From: ${email.from}\nAsunto: ${subject}\nCuerpo: ${body.substring(0, 5000)}`
};
const aiItems = $input.all();
const emailItems = $('CodeProcessEmail').all(); const output = aiItems.map((item, index) => { const originalEmail = emailItems[index]?.json || {}; const aiText = item.json.text || ''; return { json: { ...originalEmail, aiResponse: aiText.trim(), canReply: !aiText.includes('NO_PUEDO_RESPONDER') } };
}); return output;
const aiItems = $input.all();
const emailItems = $('CodeProcessEmail').all(); const output = aiItems.map((item, index) => { const originalEmail = emailItems[index]?.json || {}; const aiText = item.json.text || ''; return { json: { ...originalEmail, aiResponse: aiText.trim(), canReply: !aiText.includes('NO_PUEDO_RESPONDER') } };
}); return output;
const aiItems = $input.all();
const emailItems = $('CodeProcessEmail').all(); const output = aiItems.map((item, index) => { const originalEmail = emailItems[index]?.json || {}; const aiText = item.json.text || ''; return { json: { ...originalEmail, aiResponse: aiText.trim(), canReply: !aiText.includes('NO_PUEDO_RESPONDER') } };
}); return output;
const escapeHtml = (value) => { return String(value || '') .replace(/&/g, '&') .replace(/</g, '<') .replace(/>/g, '>');
};
const items = $input.all(); let text = '';
items.forEach((item, index) => { const subject = escapeHtml(item.json.subject || 'Sin asunto'); const aiResponse = escapeHtml(item.json.aiResponse || ''); text += `${index + 1}) ${subject}: ${aiResponse}\n━━━━━━━━━━━━━━━━━━━━\n`;
}); // ---- split into chunks ----
const chunkSize = 3900;
const header = `━━━━━━━━━━━━━━━━━━━━\n<b>Recibiste los siguientes correos:</b>\n\n`; const fullText = header + text;
const totalParts = Math.ceil(fullText.length / chunkSize) || 1; const output = [];
for (let i = 0; i < fullText.length; i += chunkSize) { const part = Math.floor(i / chunkSize) + 1; output.push({ json: { text: `[${part}/${totalParts}]\n${fullText.slice(i, i + chunkSize)}` } });
} return output;
const escapeHtml = (value) => { return String(value || '') .replace(/&/g, '&') .replace(/</g, '<') .replace(/>/g, '>');
};
const items = $input.all(); let text = '';
items.forEach((item, index) => { const subject = escapeHtml(item.json.subject || 'Sin asunto'); const aiResponse = escapeHtml(item.json.aiResponse || ''); text += `${index + 1}) ${subject}: ${aiResponse}\n━━━━━━━━━━━━━━━━━━━━\n`;
}); // ---- split into chunks ----
const chunkSize = 3900;
const header = `━━━━━━━━━━━━━━━━━━━━\n<b>Recibiste los siguientes correos:</b>\n\n`; const fullText = header + text;
const totalParts = Math.ceil(fullText.length / chunkSize) || 1; const output = [];
for (let i = 0; i < fullText.length; i += chunkSize) { const part = Math.floor(i / chunkSize) + 1; output.push({ json: { text: `[${part}/${totalParts}]\n${fullText.slice(i, i + chunkSize)}` } });
} return output;
const escapeHtml = (value) => { return String(value || '') .replace(/&/g, '&') .replace(/</g, '<') .replace(/>/g, '>');
};
const items = $input.all(); let text = '';
items.forEach((item, index) => { const subject = escapeHtml(item.json.subject || 'Sin asunto'); const aiResponse = escapeHtml(item.json.aiResponse || ''); text += `${index + 1}) ${subject}: ${aiResponse}\n━━━━━━━━━━━━━━━━━━━━\n`;
}); // ---- split into chunks ----
const chunkSize = 3900;
const header = `━━━━━━━━━━━━━━━━━━━━\n<b>Recibiste los siguientes correos:</b>\n\n`; const fullText = header + text;
const totalParts = Math.ceil(fullText.length / chunkSize) || 1; const output = [];
for (let i = 0; i < fullText.length; i += chunkSize) { const part = Math.floor(i / chunkSize) + 1; output.push({ json: { text: `[${part}/${totalParts}]\n${fullText.slice(i, i + chunkSize)}` } });
} return output;
const from = $input.item.json.from;
const allowedDomains = ['yourdomain.com', 'client.com'];
const domain = from.split('@')[1];
return allowedDomains.includes(domain);
const from = $input.item.json.from;
const allowedDomains = ['yourdomain.com', 'client.com'];
const domain = from.split('@')[1];
return allowedDomains.includes(domain);
const from = $input.item.json.from;
const allowedDomains = ['yourdomain.com', 'client.com'];
const domain = from.split('@')[1];
return allowedDomains.includes(domain); - Reads incoming emails via IMAP
- Analyzes them with DeepSeek using a custom knowledge base
- Replies automatically when the model has enough context
- Notifies you via Telegram when it needs human review - A server with n8n up and running (if you don't have one, follow this installation guide)
- An email account with IMAP access (ZohoMail, Gmail, Outlook, or any provider that supports it)
- A DeepSeek API key (platform.deepseek.com)
- A Telegram bot created via https://t.me/BotFather - DEEPSEEK_API_KEY
- Endpoint URL: https://api.deepseek.com/v1/chat/completions
- Recommended model: deepseek-chat - Open Telegram and search for @userinfobot
- Start the conversation with Start
- The bot replies automatically with your info. Look for the line that says Id: — that number is your Chat ID - In the Credential field, configure the following (values and setup vary by email provider): - User: your email
- Password: your password or app password
- Host: your IMAP server (e.g. imap.gmail.com)
- Secure: true - In the rest of the form, fill in: - Mailbox Name: the mailbox to pull emails from, defaults to INBOX
- Action: Mark as Read — this way every processed email gets marked as read. - In DeepSeek Chat Model, just configure the credentials: - Credential: select or create a DeepSeek account credential API Key: your DeepSeek key
- API Key: your DeepSeek key
- Model: deepseek-v4-flash - API Key: your DeepSeek key - In Basic LLM Chain (processor): - Source for Prompt: Define below
- Prompt (User Message): Analyze this email and provide a short, clear response to send via Telegram.
{{ $json.chatInput }}
- Chat Messages: Type: System → Message: {{ $json.knowledgeBase }}
- Type: System → Message: {{ $json.knowledgeBase }}
- Require Specific Output Format: disabled - Type: System → Message: {{ $json.knowledgeBase }} - It grabs the original email data (subject, from, body, etc.)
- It adds aiResponse with the clean response from DeepSeek
- It adds canReply (true/false) to decide whether to auto-reply - Yes (true) → goes to SMTP send
- No (false) → goes to Telegram notification - Credential: a window will open for you to register your SMTP credentials: User
Password
Host
Port
SSL
- From Email: we'll tell it to reply from the same address they wrote to: {{ $json.to }}
- To: the person who wrote in: {{ $json.from }}
- Subject: Re: {{ $('CodeProcessEmail').item.json.subject }}
- Email Format: HTML
- Text: {{ $json.aiResponse }} - Add a Code node (JavaScript) in Run Once for All Items mode with the following code: - Add an HTTP Request node to send each of the messages we defined:
- Method: POST
- URL: https://api.telegram.org/bot{YourTelegramToken,format:0000:xxxxxx}/sendMessage
- Authentication: none
- SendBody: true
- Body Content Type: JSON
- Specify Body: Using Fields Below chat_id: your Telegram conversation ID text: {{ $json.text }} parse_mode: HTML disable_web_page_preview: TRUE
- chat_id: your Telegram conversation ID
- text: {{ $json.text }}
- parse_mode: HTML
- disable_web_page_preview: TRUE - chat_id: your Telegram conversation ID
- text: {{ $json.text }}
- parse_mode: HTML
- disable_web_page_preview: TRUE - Run it manually by clicking the Execute Workflow button (top right). This triggers the workflow immediately without waiting for automatic polling.
- Send yourself a test email with a question that's covered in your knowledge base.
- Check that you receive the automatic reply in the test sender's inbox.
- Send another email with something outside your knowledge base.
- You should receive a Telegram notification with the email content. - Reads emails via IMAP without missing any
- Analyzes them with DeepSeek against your own knowledge base
- Replies automatically when it can
- Notifies you via Telegram when it needs your input