// app/api/contact/route.js import { NextResponse } from 'next/server'; import nodemailer from 'nodemailer'; // 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, }; return nodemailer.createTransport(config || defaultConfig); }; // Handle Contact Form async function handleContact(data, smtpConfig = null) { console.log('šŸ“ Processing contact form...'); const transporter = createTransporter(smtpConfig); const mailOptions = { from: process.env.ZOHO_EMAIL, to: process.env.RECIPIENT_EMAIL, 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}

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}

`, }; console.log('šŸ“§ Attempting to send email...'); const result = await transporter.sendMail(mailOptions); console.log('āœ… Email sent successfully:', result.messageId); return result; } // Handle Career Form async function handleCareer(data, smtpConfig = null) { console.log('šŸ“ Processing career form...'); const transporter = createTransporter(smtpConfig); const mailOptions = { from: process.env.ZOHO_EMAIL, to: process.env.RECIPIENT_EMAIL, 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}

Roles of Interest: ${data.roles}

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}

`, 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 application email sent successfully:', result.messageId); return result; } // POST handler with comprehensive debugging export async function POST(request) { console.log('\nšŸš€ === CONTACT API ROUTE STARTED ==='); try { // Step 1: Test environment variables const envTest = testEnvironmentVariables(); if (!envTest) { return NextResponse.json( { 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 } ); } // Step 3: Parse request body console.log('\nšŸ“ === PARSING REQUEST ==='); let body; try { body = await request.json(); 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:', parseError.message); return NextResponse.json( { error: 'Invalid JSON in request body' }, { status: 400 } ); } const { type, ...data } = body; // Step 4: Validate request if (!type) { return NextResponse.json( { error: 'Form type is required' }, { status: 400 } ); } if (!['contact', 'career'].includes(type)) { return NextResponse.json( { error: 'Invalid form type' }, { status: 400 } ); } // 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 }, { status: 200 } ); } catch (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('Full error:', error); // Determine specific error response let errorMessage = 'Failed to send email'; let statusCode = 500; if (error.code === 'EAUTH') { errorMessage = 'Email authentication failed. Check your Zoho credentials.'; } else if (error.code === 'ECONNECTION' || error.code === 'ETIMEDOUT') { errorMessage = 'Connection to email server failed.'; } else if (error.message?.includes('Invalid login')) { errorMessage = 'Invalid email or password. Please check your Zoho app password.'; } return NextResponse.json( { error: errorMessage, details: error.message, code: error.code || 'UNKNOWN' }, { status: statusCode } ); } }