From 82880799854edf0e2d1dea31219ac8ed41e81636 Mon Sep 17 00:00:00 2001 From: mukesh13 Date: Tue, 26 Aug 2025 13:52:37 +0530 Subject: [PATCH] SMTP Config --- app/api/contact/route.js | 350 +++++++++++++++++++++++---------------- 1 file changed, 205 insertions(+), 145 deletions(-) diff --git a/app/api/contact/route.js b/app/api/contact/route.js index 07c5ecc..49d1c64 100644 --- a/app/api/contact/route.js +++ b/app/api/contact/route.js @@ -1,173 +1,241 @@ // app/api/contact/route.js -// āŒ REMOVE "use client" from here - API routes must NOT have this directive - import { NextResponse } from 'next/server'; import nodemailer from 'nodemailer'; -// Create transporter with Zoho configuration -const createTransport = () => { - return nodemailer.createTransport({ +// Test environment variables function +function testEnvironmentVariables() { + console.log('\nšŸ” === TESTING ENVIRONMENT VARIABLES ==='); + + const envVars = { + ZOHO_EMAIL: process.env.ZOHO_EMAIL, + ZOHO_PASSWORD: process.env.ZOHO_PASSWORD, + RECIPIENT_EMAIL: process.env.RECIPIENT_EMAIL, + }; + + console.log('Environment check:'); + Object.entries(envVars).forEach(([key, value]) => { + if (value) { + console.log(`āœ… ${key}: ${key === 'ZOHO_PASSWORD' ? value.slice(0, 4) + '*'.repeat(value.length - 4) : value}`); + } else { + console.log(`āŒ ${key}: MISSING`); + } + }); + + const missing = Object.entries(envVars).filter(([key, value]) => !value); + if (missing.length > 0) { + console.log('āŒ Missing variables:', missing.map(([key]) => key).join(', ')); + return false; + } + + console.log('āœ… All environment variables are set'); + return true; +} + +// Test SMTP connection with multiple configurations +async function testSMTPConnection() { + console.log('\nšŸ” === TESTING SMTP CONNECTION ==='); + + // Configuration 1: SSL with port 465 (Recommended for Zoho) + const config1 = { + host: 'smtp.zoho.com', + port: 465, + secure: true, // SSL + auth: { + user: process.env.ZOHO_EMAIL, + pass: process.env.ZOHO_PASSWORD, + }, + debug: false, + logger: false, + }; + + // Configuration 2: STARTTLS with port 587 + const config2 = { host: 'smtp.zoho.com', port: 587, secure: false, + requireTLS: true, + auth: { + user: process.env.ZOHO_EMAIL, + pass: process.env.ZOHO_PASSWORD, + }, + debug: false, + logger: false, + }; + + // Configuration 3: Alternative host for domain emails + const config3 = { + host: 'smtp.zoho.in', + port: 465, + secure: true, + auth: { + user: process.env.ZOHO_EMAIL, + pass: process.env.ZOHO_PASSWORD, + }, + debug: false, + logger: false, + }; + + const configs = [ + { name: 'SSL Port 465 (smtp.zoho.com)', config: config1 }, + { name: 'STARTTLS Port 587 (smtp.zoho.com)', config: config2 }, + { name: 'SSL Port 465 (smtp.zoho.in)', config: config3 } + ]; + + for (const { name, config } of configs) { + try { + console.log(`šŸ“” Testing ${name}...`); + const transporter = nodemailer.createTransport(config); + await transporter.verify(); + console.log(`āœ… SMTP connection successful with ${name}`); + return { success: true, transporter, config }; + } catch (error) { + console.log(`āŒ ${name} failed: ${error.message}`); + } + } + + return { + success: false, + error: new Error('All SMTP configurations failed. Please check your credentials and enable App Password.') + }; +} + +// Create transporter with the successful configuration +const createTransporter = (config = null) => { + // Use the config that worked during testing, or fall back to SSL default + const defaultConfig = { + host: 'smtp.zoho.com', + port: 465, + secure: true, // SSL auth: { user: process.env.ZOHO_EMAIL, pass: process.env.ZOHO_PASSWORD, }, debug: true, logger: true, - }); -}; - -// Handle Newsletter Subscription -async function handleNewsletter(data) { - console.log('Processing newsletter subscription for:', data.email); - - const transporter = createTransport(); - - const mailOptions = { - from: process.env.ZOHO_EMAIL, - to: process.env.RECIPIENT_EMAIL, - subject: 'New Newsletter Subscription - Keystone Solutions', - html: ` -
-

New Newsletter Subscription

-
-

Email: ${data.email}

-

Subscribed at: ${new Date().toLocaleString()}

-
-
-

- This email was sent from your website's newsletter subscription form. -

-
- `, }; - const result = await transporter.sendMail(mailOptions); - console.log('Newsletter email sent successfully:', result.messageId); - return result; -} + return nodemailer.createTransport(config || defaultConfig); +}; // Handle Contact Form -async function handleContact(data) { - console.log('Processing contact form for:', data.fullName, data.email); +async function handleContact(data, smtpConfig = null) { + console.log('šŸ“ Processing contact form...'); - const transporter = createTransport(); + const transporter = createTransporter(smtpConfig); const mailOptions = { from: process.env.ZOHO_EMAIL, to: process.env.RECIPIENT_EMAIL, - subject: 'New Contact Form Submission - Keystone Solutions', + replyTo: data.email, // User can reply directly to the person who submitted the form + subject: `New Contact Form Submission from ${data.fullName} - Keystone Solutions`, html: `

New Contact Form Submission

Full Name: ${data.fullName}

-

Email: ${data.email}

+

Email: ${data.email}

Phone: ${data.phone || 'Not provided'}

Message:

${data.message || 'No message provided'}

Submitted at: ${new Date().toLocaleString()}

+
+

+ šŸ’” Tip: Click "Reply" to respond directly to ${data.fullName} at ${data.email} +

-
-

- This email was sent from your website's contact form. -

`, }; + console.log('šŸ“§ Attempting to send email...'); const result = await transporter.sendMail(mailOptions); - console.log('Contact email sent successfully:', result.messageId); + console.log('āœ… Email sent successfully:', result.messageId); return result; } // Handle Career Form -async function handleCareer(data) { - console.log('Processing career form for:', data.fullName, data.email); +async function handleCareer(data, smtpConfig = null) { + console.log('šŸ“ Processing career form...'); - const transporter = createTransport(); - - const attachments = []; - - // Handle file attachment if present - if (data.resume) { - console.log('Resume file attached:', data.resume.name); - attachments.push({ - filename: data.resume.name, - content: Buffer.from(data.resume.data, 'base64'), - contentType: data.resume.type, - }); - } + const transporter = createTransporter(smtpConfig); const mailOptions = { from: process.env.ZOHO_EMAIL, to: process.env.RECIPIENT_EMAIL, - subject: 'New Career Application - Keystone Solutions', + replyTo: data.email, // User can reply directly to the applicant + subject: `New Career Application from ${data.fullName} for ${data.roles} - Keystone Solutions`, html: `

New Career Application

Full Name: ${data.fullName}

-

Email: ${data.email}

-

Phone: ${data.phone}

+

Email: ${data.email}

+

Phone: ${data.phone}

Roles of Interest: ${data.roles}

-

Resume: ${data.resume ? 'Attached' : 'Not provided'}

+

Resume: ${data.resume ? `šŸ“Ž ${data.resume.name} (attached)` : 'Not provided'}

Applied at: ${new Date().toLocaleString()}

+
+

+ šŸ’” Tip: Click "Reply" to respond directly to ${data.fullName} at ${data.email} +

-
-

- This email was sent from your website's career application form. -

`, - attachments: attachments, + attachments: data.resume ? [{ + filename: data.resume.name, + content: data.resume.data, + encoding: 'base64' + }] : [] }; + console.log('šŸ“§ Attempting to send career application email...'); const result = await transporter.sendMail(mailOptions); - console.log('Career email sent successfully:', result.messageId); + console.log('āœ… Career application email sent successfully:', result.messageId); return result; } -// POST handler for all form submissions +// POST handler with comprehensive debugging export async function POST(request) { - console.log('\nšŸš€ === EMAIL API ROUTE STARTED ==='); + console.log('\nšŸš€ === CONTACT API ROUTE STARTED ==='); try { - // Check environment variables first - const requiredEnvVars = { - ZOHO_EMAIL: process.env.ZOHO_EMAIL, - ZOHO_PASSWORD: process.env.ZOHO_PASSWORD, - RECIPIENT_EMAIL: process.env.RECIPIENT_EMAIL, - }; - - console.log('Environment variables check:'); - Object.entries(requiredEnvVars).forEach(([key, value]) => { - console.log(`${key}: ${value ? 'āœ… Set' : 'āŒ Missing'}`); - }); - console.log( - 'Loaded password (first 3 chars):', - process.env.ZOHO_PASSWORD?.slice(0, 3) - ); - - if (!requiredEnvVars.ZOHO_EMAIL || !requiredEnvVars.ZOHO_PASSWORD || !requiredEnvVars.RECIPIENT_EMAIL) { - console.error('āŒ Missing required environment variables'); + // Step 1: Test environment variables + const envTest = testEnvironmentVariables(); + if (!envTest) { return NextResponse.json( - { error: 'Email configuration missing' }, + { + error: 'Environment variables missing', + details: 'Please check your .env.local file' + }, + { status: 500 } + ); + } + + // Step 2: Test SMTP connection + const smtpTest = await testSMTPConnection(); + if (!smtpTest.success) { + return NextResponse.json( + { + error: 'SMTP connection failed', + details: smtpTest.error.message, + code: smtpTest.error.code + }, { status: 500 } ); } - // Parse request body + // Step 3: Parse request body + console.log('\nšŸ“ === PARSING REQUEST ==='); let body; try { body = await request.json(); - console.log('āœ… Request body parsed successfully'); + console.log('āœ… Request parsed successfully'); + console.log('Form type:', body.type); + console.log('Data keys:', Object.keys(body).join(', ')); } catch (parseError) { - console.error('āŒ Failed to parse request body:', parseError); + console.error('āŒ Failed to parse request:', parseError.message); return NextResponse.json( { error: 'Invalid JSON in request body' }, { status: 400 } @@ -175,92 +243,84 @@ export async function POST(request) { } const { type, ...data } = body; - console.log(`šŸ“ Form type: ${type}`); - console.log(`šŸ“‹ Form data keys: ${Object.keys(data).join(', ')}`); + // Step 4: Validate request if (!type) { - console.error('āŒ No form type specified'); return NextResponse.json( { error: 'Form type is required' }, { status: 400 } ); } - // Route to appropriate handler based on form type - let result; - switch (type) { - case 'newsletter': - if (!data.email) { - console.error('āŒ Newsletter: Email is required'); - return NextResponse.json({ error: 'Email is required' }, { status: 400 }); - } - result = await handleNewsletter(data); - break; - - case 'contact': - if (!data.fullName || !data.email) { - console.error('āŒ Contact: Full name and email are required'); - return NextResponse.json({ error: 'Full name and email are required' }, { status: 400 }); - } - result = await handleContact(data); - break; - - case 'career': - if (!data.fullName || !data.email || !data.phone) { - console.error('āŒ Career: Full name, email, and phone are required'); - return NextResponse.json({ error: 'Full name, email, and phone are required' }, { status: 400 }); - } - result = await handleCareer(data); - break; - - default: - console.error('āŒ Invalid form type:', type); - return NextResponse.json({ error: 'Invalid form type' }, { status: 400 }); + if (!['contact', 'career'].includes(type)) { + return NextResponse.json( + { error: 'Invalid form type' }, + { status: 400 } + ); } - console.log('āœ… Email sent successfully!'); - console.log('šŸ“§ Message ID:', result.messageId); - console.log('šŸŽ‰ === EMAIL API ROUTE SUCCESS ===\n'); + // Common validation + if (!data.fullName || !data.email) { + return NextResponse.json( + { error: 'Full name and email are required' }, + { status: 400 } + ); + } + // Career form specific validation + if (type === 'career') { + if (!data.phone || !data.roles) { + return NextResponse.json( + { error: 'Phone and roles are required for career applications' }, + { status: 400 } + ); + } + } + + // Step 5: Send email based on form type + console.log('\nšŸ“§ === SENDING EMAIL ==='); + let result; + + if (type === 'contact') { + result = await handleContact(data, smtpTest.config); + } else if (type === 'career') { + result = await handleCareer(data, smtpTest.config); + } + + console.log('šŸŽ‰ === SUCCESS ==='); return NextResponse.json( { message: 'Email sent successfully', messageId: result.messageId, - type: type + type: type }, { status: 200 } ); } catch (error) { - console.error('\nšŸ’„ === EMAIL API ROUTE ERROR ==='); + console.error('\nšŸ’„ === ERROR OCCURRED ==='); console.error('Error name:', error.name); console.error('Error message:', error.message); console.error('Error code:', error.code); - console.error('Error stack:', error.stack); + console.error('Full error:', error); - // Provide more specific error messages + // Determine specific error response let errorMessage = 'Failed to send email'; let statusCode = 500; if (error.code === 'EAUTH') { - errorMessage = 'Authentication failed. Please check your Zoho email and app password.'; - console.error('šŸ” Authentication issue - check ZOHO_EMAIL and ZOHO_PASSWORD'); + errorMessage = 'Email authentication failed. Check your Zoho credentials.'; } else if (error.code === 'ECONNECTION' || error.code === 'ETIMEDOUT') { - errorMessage = 'Connection to email server failed. Please try again.'; - console.error('🌐 Network connection issue'); - } else if (error.code === 'EMESSAGE') { - errorMessage = 'Invalid email message format.'; - statusCode = 400; - console.error('šŸ“§ Email format issue'); + errorMessage = 'Connection to email server failed.'; + } else if (error.message?.includes('Invalid login')) { + errorMessage = 'Invalid email or password. Please check your Zoho app password.'; } - console.error('šŸ’„ === END ERROR DETAILS ===\n'); - return NextResponse.json( { error: errorMessage, details: error.message, - code: error.code + code: error.code || 'UNKNOWN' }, { status: statusCode } );