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