// 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 }
);
}
}