From 6074d45c540bbf3cad7956550a1e3308fe0df05b Mon Sep 17 00:00:00 2001 From: Ritam-Vaskar Date: Mon, 12 Jan 2026 22:16:54 +0530 Subject: [PATCH 1/9] Update CORS configuration to include new allowed origin and restrict access in production --- index.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index 8aa91cd..e6720ff 100644 --- a/index.js +++ b/index.js @@ -121,13 +121,14 @@ app.use(cors({ "http://localhost:5173", "http://localhost:3000", "https://fedkiit.com", - "https://www.fedkiit.com" + "https://www.fedkiit.com", + "https://awsapi2.fedkiit.com" ]; if (allowedOrigins.includes(origin)) { callback(null, true); } else { - callback(null, true); // Allow all in dev, restrict in production + callback(new Error('Not allowed by CORS')); } }, methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"], From 77747c448f00a0a8cccb72f0052ee564c747a6c5 Mon Sep 17 00:00:00 2001 From: Ritam-Vaskar Date: Mon, 12 Jan 2026 22:30:00 +0530 Subject: [PATCH 2/9] Update CORS configuration to allow all origins --- index.js | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/index.js b/index.js index e6720ff..452100c 100644 --- a/index.js +++ b/index.js @@ -114,22 +114,8 @@ app.use(cookieParser()); app.use(cors({ origin: function (origin, callback) { - // Allow requests with no origin (like mobile apps or curl) - if (!origin) return callback(null, true); - - const allowedOrigins = [ - "http://localhost:5173", - "http://localhost:3000", - "https://fedkiit.com", - "https://www.fedkiit.com", - "https://awsapi2.fedkiit.com" - ]; - - if (allowedOrigins.includes(origin)) { - callback(null, true); - } else { - callback(new Error('Not allowed by CORS')); - } + // Allow all origins by returning the requesting origin + callback(null, origin || '*'); }, methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"], credentials: true, From ad9e4c528593608335b85917efbda9545bc3f2ec Mon Sep 17 00:00:00 2001 From: Ritam-Vaskar Date: Tue, 13 Jan 2026 01:54:07 +0530 Subject: [PATCH 3/9] Update CORS configuration to allow all origins with credentials --- index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index 452100c..912a324 100644 --- a/index.js +++ b/index.js @@ -114,8 +114,8 @@ app.use(cookieParser()); app.use(cors({ origin: function (origin, callback) { - // Allow all origins by returning the requesting origin - callback(null, origin || '*'); + // Allow all origins - return true to allow any origin with credentials + callback(null, true); }, methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"], credentials: true, From d8bdb3dcc919386c4a54208a9dbcd7057bf77030 Mon Sep 17 00:00:00 2001 From: Ritam-Vaskar Date: Tue, 13 Jan 2026 02:07:01 +0530 Subject: [PATCH 4/9] Update CORS configuration to restrict allowed origins --- index.js | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/index.js b/index.js index 912a324..e038098 100644 --- a/index.js +++ b/index.js @@ -107,18 +107,29 @@ const PORT = process.env.PORT || 3000; const frontendUrl = process.env.DOMAIN; console.log("Frontend URL:", frontendUrl); + +const allowedOrigins = [ + "https://www.fedkiit.com", + "https://fedkiit.com", + "http://localhost:5173", + "http://localhost:3000" +]; + // Middlewares app.use(express.json({ limit: '16kb' })); app.use(express.urlencoded({ extended: true, limit: "16kb" })); app.use(cookieParser()); app.use(cors({ - origin: function (origin, callback) { - // Allow all origins - return true to allow any origin with credentials - callback(null, true); - }, - methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"], - credentials: true, + origin: (origin, callback) => { + if (!origin) return callback(null, true); + if (allowedOrigins.includes(origin)) { + return callback(null, origin); + } + callback(null, false); + }, + credentials: true, + methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"], })); app.options('*', cors()); // handle preflight requests From 67139829e2c71381fd5023daaddf851440f308d1 Mon Sep 17 00:00:00 2001 From: Ritam-Vaskar Date: Tue, 13 Jan 2026 02:23:15 +0530 Subject: [PATCH 5/9] Refactor CORS middleware to use shared options for normal and preflight requests --- index.js | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/index.js b/index.js index e038098..60d3e4f 100644 --- a/index.js +++ b/index.js @@ -115,23 +115,30 @@ const allowedOrigins = [ "http://localhost:3000" ]; -// Middlewares -app.use(express.json({ limit: '16kb' })); -app.use(express.urlencoded({ extended: true, limit: "16kb" })); -app.use(cookieParser()); - -app.use(cors({ +// Shared CORS options for both normal and preflight requests +const corsOptions = { origin: (origin, callback) => { if (!origin) return callback(null, true); if (allowedOrigins.includes(origin)) { - return callback(null, origin); + return callback(null, true); // reflect request origin } callback(null, false); }, credentials: true, methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"], -})); -app.options('*', cors()); // handle preflight requests + allowedHeaders: ["Content-Type", "Authorization", "X-Requested-With"], + exposedHeaders: ["Content-Length"] +}; + +// Middlewares +app.use(express.json({ limit: '16kb' })); +app.use(express.urlencoded({ extended: true, limit: "16kb" })); +app.use(cookieParser()); + +// Apply CORS for normal requests +app.use(cors(corsOptions)); +// Ensure preflight responses use the same options (no wildcard when credentials) +app.options('*', cors(corsOptions)); // const allowedOrigins = [ // "https://fedkiit.com", From 5ff99df52a817fa5e7ac9407e7c85fc6048550a4 Mon Sep 17 00:00:00 2001 From: Ritam Vaskar Date: Thu, 15 Jan 2026 00:35:28 +0530 Subject: [PATCH 6/9] Refactor Dockerfile for efficiency and Puppeteer config Updated Dockerfile to streamline package installation and skip Chromium download. --- Dockerfile | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/Dockerfile b/Dockerfile index fad2978..88995f6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -33,8 +33,7 @@ RUN apt-get update && apt-get install -y \ xdg-utils \ wget \ --no-install-recommends && \ - apt-get clean && \ - rm -rf /var/lib/apt/lists/* + apt-get clean && rm -rf /var/lib/apt/lists/* # Set working directory WORKDIR /app @@ -43,17 +42,20 @@ WORKDIR /app ARG DATABASE_URL ENV DATABASE_URL=${DATABASE_URL} -# Copy package files and install deps +# Skip Puppeteer Chromium download +ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true + +# Copy package files and install dependencies COPY package*.json ./ -RUN npm install --omit=dev +RUN npm ci --omit=dev -# Copy source +# Copy source code COPY . . # Make build.sh executable RUN chmod +x ./build.sh -# Expose app port +# Expose port EXPOSE 5000 # Start From b65fa00552b72987b2327bc2d9890c77dd3ffcf5 Mon Sep 17 00:00:00 2001 From: Krishna Das Date: Thu, 15 Jan 2026 01:59:39 +0530 Subject: [PATCH 7/9] feat: Migrate email from Nodemailer to Resend API with fallback support --- config/nodeMailer.js | 19 ++++++ config/resend.js | 7 ++ package-lock.json | 53 +++++++++++++++ package.json | 1 + utils/email/nodeMailer.js | 133 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 213 insertions(+) create mode 100644 config/resend.js diff --git a/config/nodeMailer.js b/config/nodeMailer.js index effadfd..bc74138 100644 --- a/config/nodeMailer.js +++ b/config/nodeMailer.js @@ -1,4 +1,12 @@ // config/nodeMailer.js +// DEPRECATED: This file has been replaced by Resend API +// See: config/resend.js and utils/email/nodeMailer.js for new implementation +// Date: January 2026 + +/* ============================================================ + ORIGINAL NODEMAILER CONFIGURATION (COMMENTED OUT) + ============================================================ + const nodemailer = require("nodemailer"); // Primary transporter (e.g., Gmail) @@ -43,3 +51,14 @@ module.exports = { tertiary: mailTransporterTertiary, mailerSend: mailTransporterMailerSend, }; + +============================================================ */ + +// Export empty object to prevent import errors during transition +// This file is no longer used - Resend API is used instead +module.exports = { + primary: null, + secondary: null, + tertiary: null, + mailerSend: null, +}; diff --git a/config/resend.js b/config/resend.js new file mode 100644 index 0000000..85eed5c --- /dev/null +++ b/config/resend.js @@ -0,0 +1,7 @@ +// config/resend.js +const { Resend } = require('resend'); + +// Initialize Resend with API key from environment variable +const resend = new Resend(process.env.RESEND_API_KEY); + +module.exports = { resend }; diff --git a/package-lock.json b/package-lock.json index 06b43cd..a8b2efa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -41,6 +41,7 @@ "puppeteer-extra-plugin-stealth": "^2.11.2", "qrcode": "^1.5.4", "react-otp-input": "^3.1.1", + "resend": "^6.7.0", "sharp": "^0.33.4", "uuid": "^10.0.0", "xlsx": "^0.18.5" @@ -745,6 +746,12 @@ "node": ">=12" } }, + "node_modules/@stablelib/base64": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/base64/-/base64-1.0.1.tgz", + "integrity": "sha512-1bnPQqSxSuc3Ii6MhBysoWCg58j97aUjuCSZrGSmDxNqtytIi0k8utUenAwTZN4V5mXXYGsVUI9zeBqy+jBOSQ==", + "license": "MIT" + }, "node_modules/@tootallnate/quickjs-emscripten": { "version": "0.23.0", "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", @@ -2379,6 +2386,12 @@ "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", "license": "MIT" }, + "node_modules/fast-sha256": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-sha256/-/fast-sha256-1.3.0.tgz", + "integrity": "sha512-n11RGP/lrWEFI/bWdygLxhI+pVeo1ZYIVwvvPkW7azl/rOy+F3HYRZ2K5zeE9mmkhQppyv9sQFx0JM9UabnpPQ==", + "license": "Unlicense" + }, "node_modules/fd-slicer": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", @@ -4870,6 +4883,26 @@ "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", "license": "ISC" }, + "node_modules/resend": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/resend/-/resend-6.7.0.tgz", + "integrity": "sha512-2ZV0NDZsh4Gh+Nd1hvluZIitmGJ59O4+OxMufymG6Y8uz1Jgt2uS1seSENnkIUlmwg7/dwmfIJC9rAufByz7wA==", + "license": "MIT", + "dependencies": { + "svix": "1.84.1" + }, + "engines": { + "node": ">=20" + }, + "peerDependencies": { + "@react-email/render": "*" + }, + "peerDependenciesMeta": { + "@react-email/render": { + "optional": true + } + } + }, "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -5309,6 +5342,16 @@ "node": ">=0.8" } }, + "node_modules/standardwebhooks": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/standardwebhooks/-/standardwebhooks-1.0.0.tgz", + "integrity": "sha512-BbHGOQK9olHPMvQNHWul6MYlrRTAOKn03rOe4A8O3CLWhNf4YHBqq2HJKKC+sfqpxiBY52pNeesD6jIiLDz8jg==", + "license": "MIT", + "dependencies": { + "@stablelib/base64": "^1.0.0", + "fast-sha256": "^1.3.0" + } + }, "node_modules/statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", @@ -5392,6 +5435,16 @@ "node": ">=4" } }, + "node_modules/svix": { + "version": "1.84.1", + "resolved": "https://registry.npmjs.org/svix/-/svix-1.84.1.tgz", + "integrity": "sha512-K8DPPSZaW/XqXiz1kEyzSHYgmGLnhB43nQCMeKjWGCUpLIpAMMM8kx3rVVOSm6Bo6EHyK1RQLPT4R06skM/MlQ==", + "license": "MIT", + "dependencies": { + "standardwebhooks": "1.0.0", + "uuid": "^10.0.0" + } + }, "node_modules/tar-fs": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.3.tgz", diff --git a/package.json b/package.json index 5703c01..05733d2 100644 --- a/package.json +++ b/package.json @@ -41,6 +41,7 @@ "puppeteer-extra-plugin-stealth": "^2.11.2", "qrcode": "^1.5.4", "react-otp-input": "^3.1.1", + "resend": "^6.7.0", "sharp": "^0.33.4", "uuid": "^10.0.0", "xlsx": "^0.18.5" diff --git a/utils/email/nodeMailer.js b/utils/email/nodeMailer.js index f0ed3fe..531217d 100644 --- a/utils/email/nodeMailer.js +++ b/utils/email/nodeMailer.js @@ -1,3 +1,134 @@ +// RESEND API IMPLEMENTATION WITH FALLBACK +// Replaced Nodemailer with Resend API for email sending +// Supports multiple sender domains with automatic fallback +// Date: January 2026 + +const { resend } = require("../../config/resend"); + +/** + * Get list of sender emails from environment variables + * Supports EMAIL_FROM, EMAIL_FROM_2, EMAIL_FROM_3, etc. + * @returns {Array} Array of sender emails + */ +function getSenderEmails() { + const senders = []; + + // Primary sender + if (process.env.EMAIL_FROM) { + senders.push(process.env.EMAIL_FROM); + } + + // Secondary sender + if (process.env.EMAIL_FROM_2) { + senders.push(process.env.EMAIL_FROM_2); + } + + // Tertiary sender + if (process.env.EMAIL_FROM_3) { + senders.push(process.env.EMAIL_FROM_3); + } + + // Add more as needed (EMAIL_FROM_4, EMAIL_FROM_5, etc.) + for (let i = 4; i <= 10; i++) { + const envKey = `EMAIL_FROM_${i}`; + if (process.env[envKey]) { + senders.push(process.env[envKey]); + } + } + + // Default fallback if no senders configured + if (senders.length === 0) { + senders.push('FED KIIT Compliance '); + } + + return senders; +} + +/** + * Send email using Resend API with automatic fallback to secondary domains + * @param {string} to - Recipient email address + * @param {string} subject - Email subject + * @param {string} htmlContent - HTML content of the email + * @param {string} textContent - Plain text content (optional, auto-generated from HTML if not provided) + * @param {Array} attachments - Array of attachment objects (optional) + * Format: [{ filename: 'file.pdf', content: Buffer }] + */ +async function sendMail(to, subject, htmlContent, textContent, attachments = []) { + // Get all configured sender emails + const senderEmails = getSenderEmails(); + + // Convert attachments to Resend format if present + const resendAttachments = attachments.map(att => ({ + filename: att.filename, + content: att.content, + })); + + // Build base email options + const baseEmailOptions = { + to: to, + subject: subject, + html: htmlContent, + text: textContent || htmlContent.replace(/<[^>]+>/g, ""), + reply_to: "fedkiit@gmail.com", + }; + + // Add attachments if present + if (resendAttachments.length > 0) { + baseEmailOptions.attachments = resendAttachments; + } + + // Try each sender in sequence until one succeeds + let lastError = null; + + for (let i = 0; i < senderEmails.length; i++) { + const senderEmail = senderEmails[i]; + const isLastAttempt = i === senderEmails.length - 1; + + try { + console.log(`[Resend] Attempting to send email using sender ${i + 1}: ${senderEmail}`); + + const emailOptions = { + ...baseEmailOptions, + from: senderEmail, + }; + + const { data, error } = await resend.emails.send(emailOptions); + + if (error) { + console.error(`[Resend] Sender ${i + 1} failed:`, error.message); + lastError = error; + + if (!isLastAttempt) { + console.log(`[Resend] Trying fallback sender...`); + continue; // Try next sender + } + } else { + console.log(`[Resend] Email sent successfully via sender ${i + 1}:`, data); + return data; + } + } catch (error) { + console.error(`[Resend] Sender ${i + 1} threw exception:`, error.message); + lastError = error; + + if (!isLastAttempt) { + console.log(`[Resend] Trying fallback sender...`); + continue; // Try next sender + } + } + } + + // All senders failed + console.error("[Resend] All email senders failed. Last error:", lastError); + throw new Error(`Email sending failed after trying ${senderEmails.length} sender(s): ${lastError?.message || 'Unknown error'}`); +} + +module.exports = { sendMail }; + + +/* ============================================================ + ORIGINAL NODEMAILER IMPLEMENTATION (COMMENTED OUT) + ============================================================ + const { primary, secondary, tertiary, mailerSend } = require("../../config/nodeMailer"); function sendMail(to, subject, htmlContent, textContent, attachments = []) { @@ -58,3 +189,5 @@ function sendMail(to, subject, htmlContent, textContent, attachments = []) { } module.exports = { sendMail }; + +============================================================ */ From ce59708227ca0698c422081363b78c62ecdea780 Mon Sep 17 00:00:00 2001 From: Krishna Das Date: Thu, 15 Jan 2026 02:09:40 +0530 Subject: [PATCH 8/9] feat: Migrate email from Nodemailer to Resend API --- config/resend.js | 17 +-- utils/email/nodeMailer.js | 221 ++++++++++++-------------------------- 2 files changed, 78 insertions(+), 160 deletions(-) diff --git a/config/resend.js b/config/resend.js index 85eed5c..c85da16 100644 --- a/config/resend.js +++ b/config/resend.js @@ -1,7 +1,12 @@ -// config/resend.js -const { Resend } = require('resend'); +/** + * RESEND EMAIL CONFIGURATION + * This file is kept for backward compatibility but is no longer used. + * Email sending is now handled directly in utils/email/nodeMailer.js + * + * The Resend clients are initialized directly in nodeMailer.js using: + * - RESEND_API_KEY + EMAIL_FROM (primary) + * - RESEND_API_KEY_2 + EMAIL_FROM_2 (fallback) + */ -// Initialize Resend with API key from environment variable -const resend = new Resend(process.env.RESEND_API_KEY); - -module.exports = { resend }; +// This file is deprecated - Resend clients are created in nodeMailer.js +module.exports = {}; diff --git a/utils/email/nodeMailer.js b/utils/email/nodeMailer.js index 531217d..ca30675 100644 --- a/utils/email/nodeMailer.js +++ b/utils/email/nodeMailer.js @@ -1,70 +1,45 @@ -// RESEND API IMPLEMENTATION WITH FALLBACK -// Replaced Nodemailer with Resend API for email sending -// Supports multiple sender domains with automatic fallback -// Date: January 2026 - -const { resend } = require("../../config/resend"); - /** - * Get list of sender emails from environment variables - * Supports EMAIL_FROM, EMAIL_FROM_2, EMAIL_FROM_3, etc. - * @returns {Array} Array of sender emails + * RESEND EMAIL SERVICE + * Production-ready email sending with 2-domain fallback support + * + * Environment Variables Required: + * - RESEND_API_KEY: API key for primary domain + * - EMAIL_FROM: Primary sender (e.g., "FED KIIT ") + * - RESEND_API_KEY_2: API key for fallback domain + * - EMAIL_FROM_2: Fallback sender (e.g., "FED KIIT ") */ -function getSenderEmails() { - const senders = []; - // Primary sender - if (process.env.EMAIL_FROM) { - senders.push(process.env.EMAIL_FROM); - } - - // Secondary sender - if (process.env.EMAIL_FROM_2) { - senders.push(process.env.EMAIL_FROM_2); - } - - // Tertiary sender - if (process.env.EMAIL_FROM_3) { - senders.push(process.env.EMAIL_FROM_3); - } - - // Add more as needed (EMAIL_FROM_4, EMAIL_FROM_5, etc.) - for (let i = 4; i <= 10; i++) { - const envKey = `EMAIL_FROM_${i}`; - if (process.env[envKey]) { - senders.push(process.env[envKey]); - } - } +const { Resend } = require("resend"); - // Default fallback if no senders configured - if (senders.length === 0) { - senders.push('FED KIIT Compliance '); - } +// Initialize Resend clients for both domains +const resendPrimary = process.env.RESEND_API_KEY + ? new Resend(process.env.RESEND_API_KEY) + : null; - return senders; -} +const resendSecondary = process.env.RESEND_API_KEY_2 + ? new Resend(process.env.RESEND_API_KEY_2) + : null; /** - * Send email using Resend API with automatic fallback to secondary domains + * Send email using Resend API with automatic fallback + * Tries primary domain first, falls back to secondary if primary fails + * * @param {string} to - Recipient email address * @param {string} subject - Email subject * @param {string} htmlContent - HTML content of the email - * @param {string} textContent - Plain text content (optional, auto-generated from HTML if not provided) - * @param {Array} attachments - Array of attachment objects (optional) - * Format: [{ filename: 'file.pdf', content: Buffer }] + * @param {string} textContent - Plain text content (optional, auto-generated from HTML) + * @param {Array} attachments - Array of attachments [{filename, content}] + * @returns {Promise} - Resend response data + * @throws {Error} - If both primary and secondary fail */ async function sendMail(to, subject, htmlContent, textContent, attachments = []) { - // Get all configured sender emails - const senderEmails = getSenderEmails(); - - // Convert attachments to Resend format if present - const resendAttachments = attachments.map(att => ({ - filename: att.filename, - content: att.content, - })); + // Validate environment + if (!resendPrimary && !resendSecondary) { + throw new Error("[Email] No Resend API keys configured. Set RESEND_API_KEY in .env"); + } - // Build base email options - const baseEmailOptions = { + // Build email options + const emailOptions = { to: to, subject: subject, html: htmlContent, @@ -73,121 +48,59 @@ async function sendMail(to, subject, htmlContent, textContent, attachments = []) }; // Add attachments if present - if (resendAttachments.length > 0) { - baseEmailOptions.attachments = resendAttachments; + if (attachments && attachments.length > 0) { + emailOptions.attachments = attachments.map(att => ({ + filename: att.filename, + content: att.content, + })); } - // Try each sender in sequence until one succeeds - let lastError = null; - - for (let i = 0; i < senderEmails.length; i++) { - const senderEmail = senderEmails[i]; - const isLastAttempt = i === senderEmails.length - 1; - + // ============ TRY PRIMARY SENDER ============ + if (resendPrimary && process.env.EMAIL_FROM) { try { - console.log(`[Resend] Attempting to send email using sender ${i + 1}: ${senderEmail}`); - - const emailOptions = { - ...baseEmailOptions, - from: senderEmail, - }; - - const { data, error } = await resend.emails.send(emailOptions); + console.log(`[Email] Sending via PRIMARY: ${process.env.EMAIL_FROM}`); - if (error) { - console.error(`[Resend] Sender ${i + 1} failed:`, error.message); - lastError = error; + const { data, error } = await resendPrimary.emails.send({ + ...emailOptions, + from: process.env.EMAIL_FROM, + }); - if (!isLastAttempt) { - console.log(`[Resend] Trying fallback sender...`); - continue; // Try next sender - } - } else { - console.log(`[Resend] Email sent successfully via sender ${i + 1}:`, data); + if (!error && data) { + console.log(`[Email] SUCCESS via PRIMARY:`, data.id); return data; } - } catch (error) { - console.error(`[Resend] Sender ${i + 1} threw exception:`, error.message); - lastError = error; - if (!isLastAttempt) { - console.log(`[Resend] Trying fallback sender...`); - continue; // Try next sender - } + console.error(`[Email] PRIMARY failed:`, error?.message || "Unknown error"); + } catch (err) { + console.error(`[Email] PRIMARY exception:`, err.message); } } - // All senders failed - console.error("[Resend] All email senders failed. Last error:", lastError); - throw new Error(`Email sending failed after trying ${senderEmails.length} sender(s): ${lastError?.message || 'Unknown error'}`); -} - -module.exports = { sendMail }; - - -/* ============================================================ - ORIGINAL NODEMAILER IMPLEMENTATION (COMMENTED OUT) - ============================================================ - -const { primary, secondary, tertiary, mailerSend } = require("../../config/nodeMailer"); - -function sendMail(to, subject, htmlContent, textContent, attachments = []) { - const mailDetails = { - from: `"FED KIIT Compliance" <${process.env.MAIL_USER}>`, - to, - subject, - replyTo: "fedkiit@gmail.com", - html: htmlContent, - text: textContent || htmlContent.replace(/<[^>]+>/g, ""), - ...(attachments.length > 0 && { attachments }), - }; + // ============ TRY SECONDARY SENDER (FALLBACK) ============ + if (resendSecondary && process.env.EMAIL_FROM_2) { + try { + console.log(`[Email] Sending via SECONDARY: ${process.env.EMAIL_FROM_2}`); - // Try sending with primary - primary.sendMail(mailDetails, (err, info) => { - if (err) { - console.error("Primary email failed:", err); - - // Try fallback sender - const fallbackDetails = { - ...mailDetails, - from: process.env.MAIL_USER_SECONDARY, - }; - - secondary.sendMail(fallbackDetails, (err2, info2) => { - if (err2) { - console.error("Secondary email also failed:", err2); - - // Try tertiary sender - const tertiaryDetails = { - ...mailDetails, - from: process.env.MAIL_USER_TERTIARY, - }; - tertiary.sendMail(tertiaryDetails, (err3, info3) => { - if (err3) { - mailerSend.sendMail({ ...mailDetails, from: '"FED KIIT Compliance" ' }, (err4, info4) => { - if (err4) { - console.error("MailerSend email also failed:", err4); - } else { - console.log("MailerSend email sent successfully:", info4); - } - }); - console.error("Tertiary email also failed:", err3); - } - else { - console.log("Tertiary email sent successfully:", info3); - } - }); - } else { - console.log("Fallback email sent successfully:", info2); - } + const { data, error } = await resendSecondary.emails.send({ + ...emailOptions, + from: process.env.EMAIL_FROM_2, }); - } else { - console.log("Primary email sent successfully:", info); + if (!error && data) { + console.log(`[Email] SUCCESS via SECONDARY:`, data.id); + return data; + } + + console.error(`[Email] SECONDARY failed:`, error?.message || "Unknown error"); + throw new Error(`Email failed: ${error?.message || "Secondary sender failed"}`); + } catch (err) { + console.error(`[Email] SECONDARY exception:`, err.message); + throw err; } - }); + } + + // Both failed or not configured + throw new Error("[Email] All email senders failed or not configured"); } module.exports = { sendMail }; - -============================================================ */ From 76f4da62c0eafa3344fca70cd94b597beedf7515 Mon Sep 17 00:00:00 2001 From: MdMobid Date: Mon, 16 Feb 2026 22:22:19 +0530 Subject: [PATCH 9/9] System prompt Update - Added Faculty In Charge - Alumini Line Fixed --- controllers/chatbot/promptBuilder.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/controllers/chatbot/promptBuilder.js b/controllers/chatbot/promptBuilder.js index 2a61d5e..b27a120 100644 --- a/controllers/chatbot/promptBuilder.js +++ b/controllers/chatbot/promptBuilder.js @@ -21,7 +21,11 @@ The user query will be prepended with the current list of FED Team Members in JS 1. Use this injected team data for all questions about roles, current members, and team structure 2. The key properties in the JSON are: 'name', 'access' (role code), 'year', and 'extra' (with 'linkedin', 'github', etc.) 3. Translate the 'access' codes into friendly titles (e.g., DIRECTOR_TECHNICAL -> Director of Technical Team) -4. Founder of FED is 'Niket Raj Dwivedi', The CEO of Medial, mention only when user asks specifically *don't mention yourself in every response*. + +**NAMES TO REMEMBER:** +Mention these when asked by user (don't mention in every response) +1. Founder of FED is 'Niket Raj Dwivedi', The CEO of Medial +2. Our Faculty in Charge is 'Dr. Vishal Pradhan' **PROFESSIONAL LINK FORMATTING (CRITICAL - READ CAREFULLY):** **NEVER OUTPUT HTML TAGS!** You must ONLY use markdown syntax. @@ -111,7 +115,7 @@ Use this to personalize responses about their participation and achievements. 7. **NO RAW URLS:** NEVER show raw URLs like 'https://...' - ALWAYS use markdown links with clean text 8. **CONCISE BLOG LISTS:** When listing multiple blogs, be BRIEF - title + author + link only. No summaries for lists! 9. **MARKDOWN ONLY:** Always use proper markdown [text](url) format for links. Never output HTML tags. -10. **ALUMINI:** WHEN MENTIONS 'ALUMNI' OR A DIFFERENT NAME OTHER THAN TEAM DATA IS GIVEN JUST REPLY ONE WORD: 'ALUMINI'. +10. **ALUMINI:** WHENEVER USER MENTIONS 'ALUMNI' OR A DIFFERENT NAME NOT PRESENT IN TEAM DATA, JUST REPLY WITH ONE WORD: 'ALUMINI'. **EMAIL ESCALATION SYSTEM - CRITICAL:** You have the ability to trigger email sending by outputting a special tag. The user's NEXT message after you trigger email will be sent DIRECTLY to FED without you modifying it.