From e37f230deb4480dadb0da73fca105af0ccc7231a Mon Sep 17 00:00:00 2001 From: ROSHAN GARG Date: Wed, 7 May 2025 15:50:31 +0530 Subject: [PATCH] email send eject --- Utils/sendEmail.js | 155 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 133 insertions(+), 22 deletions(-) diff --git a/Utils/sendEmail.js b/Utils/sendEmail.js index 7ab3887..321c158 100644 --- a/Utils/sendEmail.js +++ b/Utils/sendEmail.js @@ -80,48 +80,159 @@ import nodeMailer from "nodemailer"; import { createTransport } from "nodemailer"; -// Keep the original environment variable names -const transporter = createTransport({ - host: process.env.SMPT_HOST, - port: parseInt(process.env.SMPT_PORT, 10), // Convert string to number - // service: process.env.SMPT_SERVICE, - auth: { - user: process.env.SMPT_MAIL, - pass: process.env.SMPT_PASSWORD, - }, - // Add timeout to avoid hanging connections - connectionTimeout: 10000, // 10 seconds - // Log transport operations if not in production - debug: process.env.NODE_ENV !== "production", -}); +// Test connection to SMTP server first +const testSMTPConnection = async () => { + console.log("Testing SMTP connection before sending..."); + + try { + // Create a temporary transporter for testing + const testTransporter = createTransport({ + host: process.env.SMPT_HOST, + port: parseInt(process.env.SMPT_PORT, 10), + auth: { + user: process.env.SMPT_MAIL, + pass: process.env.SMPT_PASSWORD, + }, + // Reduce timeout for testing to fail faster + connectionTimeout: 5000, + // Don't actually send emails during verification + pool: false, + }); + + // Verify connection configuration + await testTransporter.verify(); + console.log("SMTP connection test successful!"); + return true; + } catch (error) { + console.error("SMTP connection test failed:"); + console.error( + `Host: ${process.env.SMPT_HOST}, Port: ${process.env.SMPT_PORT}` + ); + console.error(`Error: ${error.message}`); + + if (error.message.includes("timeout")) { + console.error( + "CONNECTION TIMEOUT: This likely indicates a network or firewall issue." + ); + console.error( + "Your hosting provider may be blocking outgoing SMTP connections." + ); + } + + return false; + } +}; + +// Try both direct SMTP and API-based fallback approach +const createFallbackTransporter = () => { + // If we're in production and previously had timeout issues, try to use Brevo API instead + if (process.env.USE_BREVO_API === "true") { + console.log("Using Brevo API instead of SMTP"); + + // This requires installing the Brevo API library: npm install @sendinblue/client + // And setting BREVO_API_KEY in your environment variables + const SibApiV3Sdk = require("@sendinblue/client"); + + let apiInstance = new SibApiV3Sdk.TransactionalEmailsApi(); + apiInstance.setApiKey( + SibApiV3Sdk.AccountApiApiKeys.apiKey, + process.env.BREVO_API_KEY + ); + + return { + isAPI: true, + sendMail: async (options) => { + const sendSmtpEmail = new SibApiV3Sdk.SendSmtpEmail(); + sendSmtpEmail.subject = options.subject; + sendSmtpEmail.htmlContent = + options.html || "

" + (options.text || "") + "

"; + sendSmtpEmail.sender = { email: options.from || process.env.SMPT_MAIL }; + sendSmtpEmail.to = [{ email: options.to }]; + + const data = await apiInstance.sendTransacEmail(sendSmtpEmail); + return { messageId: data.messageId }; + }, + }; + } + + // Otherwise use standard SMTP + console.log("Using standard SMTP transport"); + return createTransport({ + host: process.env.SMPT_HOST, + port: parseInt(process.env.SMPT_PORT, 10), + auth: { + user: process.env.SMPT_MAIL, + pass: process.env.SMPT_PASSWORD, + }, + // Increase timeout for production + connectionTimeout: 30000, // 30 seconds + // Retry failed connections + pool: true, + maxConnections: 5, + maxMessages: 100, + rateDelta: 1000, + rateLimit: 5, + }); +}; + +// Initialize transporter +let transporter = null; +let connectionTested = false; const sendEmail = async (options) => { try { - // Log attempt to help with debugging + // Test connection first time only + if (!connectionTested) { + await testSMTPConnection(); + connectionTested = true; + } + + // Initialize transporter if needed + if (!transporter) { + transporter = createFallbackTransporter(); + } + console.log(`Attempting to send email to ${options.to}`); - // Use Promise-based API instead of callback for better error handling - const info = await transporter.sendMail(options); - console.log("Email sent successfully:", info.messageId); - return info; + // Send email (handles both SMTP and API methods) + if (transporter.isAPI) { + // API-based sending + const info = await transporter.sendMail(options); + console.log("Email sent successfully via API:", info.messageId); + return info; + } else { + // SMTP-based sending + const info = await transporter.sendMail(options); + console.log("Email sent successfully via SMTP:", info.messageId); + return info; + } } catch (error) { - // Enhanced error logging with more details console.error("Failed to send email:"); console.error("Error name:", error.name); console.error("Error message:", error.message); console.error("Error code:", error.code); + if (error.response) { console.error("SMTP Response:", error.response); } - // Re-throw so the calling code knows the email failed + // If we get timeout errors in production, suggest using API method + if ( + error.message.includes("timeout") && + process.env.NODE_ENV === "production" + ) { + console.error( + "RECOMMENDATION: Try setting USE_BREVO_API=true to use API instead of SMTP" + ); + } + throw error; } }; export default sendEmail; -// Leave the MessageBird implementation unchanged +// Leave MessageBird implementation unchanged import { initClient } from "messagebird"; const messagebird = initClient("p2YaqxU9uYx2F3d3dV8ywAFtk"); export const sendOtp = async (recipient, message) => {