327 lines
15 KiB
JavaScript
327 lines
15 KiB
JavaScript
import nodemailer from 'nodemailer';
|
|
|
|
/**
|
|
* Creates and returns a nodemailer SMTP transporter using environment variables.
|
|
*/
|
|
export function createSmtpTransporter() {
|
|
const host = process.env.SMTP_HOST;
|
|
const port = parseInt(process.env.SMTP_PORT || '465', 10);
|
|
const secure = process.env.SMTP_SECURE === 'true' || port === 465;
|
|
const user = process.env.SMTP_USER;
|
|
const pass = process.env.SMTP_PASS;
|
|
|
|
if (!host || !user || !pass) {
|
|
return null;
|
|
}
|
|
|
|
return nodemailer.createTransport({
|
|
host,
|
|
port,
|
|
secure,
|
|
auth: {
|
|
user,
|
|
pass
|
|
},
|
|
tls: {
|
|
rejectUnauthorized: false
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Sends a general contact form email via SMTP using nodemailer.
|
|
*/
|
|
export async function sendContactEmail({ name, email, phone, subject, message }) {
|
|
const transporter = createSmtpTransporter();
|
|
|
|
const toEmail = process.env.SMTP_TO || process.env.SMTP_USER || 'info@cavinfotech.com';
|
|
const fromEmail = process.env.SMTP_FROM || `"Cavin Infotech Contact Form" <${process.env.SMTP_USER || 'info@cavinfotech.com'}>`;
|
|
|
|
const mailSubject = `[Contact Inquiry] ${subject ? subject : `New Inquiry from ${name}`}`;
|
|
|
|
const htmlContent = `
|
|
<div style="font-family: 'Segoe UI', Helvetica, Arial, sans-serif; background-color: #020710; color: #f8fafc; padding: 40px 20px; max-width: 650px; margin: 0 auto; border-radius: 16px; border: 1px solid #1e293b;">
|
|
<div style="text-align: center; padding-bottom: 24px; border-bottom: 1px solid #334155;">
|
|
<h2 style="color: #ffaa00; font-size: 24px; margin: 0; font-weight: 700;">Cavin Infotech</h2>
|
|
<p style="color: #94a3b8; font-size: 14px; margin-top: 6px;">New Website Contact Form Inquiry</p>
|
|
</div>
|
|
|
|
<div style="padding: 24px 0;">
|
|
<table style="width: 100%; border-collapse: collapse; color: #e2e8f0; font-size: 15px;">
|
|
<tr>
|
|
<td style="padding: 10px 0; font-weight: 600; color: #ffaa00; width: 130px;">Name:</td>
|
|
<td style="padding: 10px 0; color: #ffffff;">${name}</td>
|
|
</tr>
|
|
<tr>
|
|
<td style="padding: 10px 0; font-weight: 600; color: #ffaa00;">Email:</td>
|
|
<td style="padding: 10px 0;"><a href="mailto:${email}" style="color: #38bdf8; text-decoration: none;">${email}</a></td>
|
|
</tr>
|
|
<tr>
|
|
<td style="padding: 10px 0; font-weight: 600; color: #ffaa00;">Phone No:</td>
|
|
<td style="padding: 10px 0; color: #ffffff;">${phone || 'Not provided'}</td>
|
|
</tr>
|
|
<tr>
|
|
<td style="padding: 10px 0; font-weight: 600; color: #ffaa00;">Subject:</td>
|
|
<td style="padding: 10px 0; color: #ffffff;">${subject || 'General Inquiry'}</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<div style="margin-top: 24px; padding: 20px; background-color: #0b1528; border-left: 4px solid #ffaa00; border-radius: 8px;">
|
|
<h4 style="margin: 0 0 10px 0; color: #94a3b8; font-size: 13px; text-transform: uppercase; letter-spacing: 0.05em;">Message:</h4>
|
|
<p style="margin: 0; color: #f1f5f9; font-size: 15px; line-height: 1.6; white-space: pre-line;">${message}</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div style="text-align: center; padding-top: 20px; border-top: 1px solid #334155; color: #64748b; font-size: 12px;">
|
|
Submitted on ${new Date().toLocaleString()} from Cavin Infotech Website
|
|
</div>
|
|
</div>
|
|
`;
|
|
|
|
const textContent = `
|
|
New Contact Inquiry - Cavin Infotech
|
|
|
|
Name: ${name}
|
|
Email: ${email}
|
|
Phone: ${phone || 'Not provided'}
|
|
Subject: ${subject || 'General Inquiry'}
|
|
|
|
Message:
|
|
${message}
|
|
|
|
Submitted on: ${new Date().toLocaleString()}
|
|
`;
|
|
|
|
if (!transporter) {
|
|
return {
|
|
success: false,
|
|
error: 'SMTP credentials not configured on the server. Please set SMTP_HOST, SMTP_USER, and SMTP_PASS in .env file.'
|
|
};
|
|
}
|
|
|
|
try {
|
|
const info = await transporter.sendMail({
|
|
from: fromEmail,
|
|
to: toEmail,
|
|
replyTo: `"${name}" <${email}>`,
|
|
subject: mailSubject,
|
|
text: textContent,
|
|
html: htmlContent
|
|
});
|
|
return { success: true, messageId: info.messageId };
|
|
} catch (err) {
|
|
return { success: false, error: err.message || 'SMTP sending failed' };
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sends a Careers application form email via SMTP using nodemailer.
|
|
*/
|
|
export async function sendCareersEmail({ name, email, phone, resumeName, message, file }) {
|
|
const transporter = createSmtpTransporter();
|
|
|
|
const toEmail = process.env.SMTP_TO || process.env.SMTP_USER || 'info@cavinfotech.com';
|
|
const noReplyEmail = process.env.SMTP_FROM || `"Cavin Infotech Careers" <${process.env.SMTP_USER || 'info@cavinfotech.com'}>`;
|
|
|
|
const mailSubject = `[Careers Application] New Application from ${name}`;
|
|
|
|
// Internal notification HTML (sent to the team)
|
|
const internalHtml = `
|
|
<div style="font-family: 'Segoe UI', Helvetica, Arial, sans-serif; background-color: #020710; color: #f8fafc; padding: 40px 20px; max-width: 650px; margin: 0 auto; border-radius: 16px; border: 1px solid #1e293b;">
|
|
<div style="text-align: center; padding-bottom: 24px; border-bottom: 1px solid #334155;">
|
|
<h2 style="color: #38bdf8; font-size: 24px; margin: 0; font-weight: 700;">Cavin Infotech</h2>
|
|
<p style="color: #94a3b8; font-size: 14px; margin-top: 6px;">New Careers / Job Application</p>
|
|
</div>
|
|
|
|
<div style="padding: 24px 0;">
|
|
<table style="width: 100%; border-collapse: collapse; color: #e2e8f0; font-size: 15px;">
|
|
<tr>
|
|
<td style="padding: 10px 0; font-weight: 600; color: #38bdf8; width: 140px;">Applicant Name:</td>
|
|
<td style="padding: 10px 0; color: #ffffff;">${name}</td>
|
|
</tr>
|
|
<tr>
|
|
<td style="padding: 10px 0; font-weight: 600; color: #38bdf8;">Email:</td>
|
|
<td style="padding: 10px 0;"><a href="mailto:${email}" style="color: #38bdf8; text-decoration: none;">${email}</a></td>
|
|
</tr>
|
|
<tr>
|
|
<td style="padding: 10px 0; font-weight: 600; color: #38bdf8;">Phone No:</td>
|
|
<td style="padding: 10px 0; color: #ffffff;">${phone || 'Not provided'}</td>
|
|
</tr>
|
|
<tr>
|
|
<td style="padding: 10px 0; font-weight: 600; color: #38bdf8;">Resume File:</td>
|
|
<td style="padding: 10px 0; color: #ffaa00; font-weight: 600;">${resumeName || 'Attached'}</td>
|
|
</tr>
|
|
</table>
|
|
|
|
${message ? `
|
|
<div style="margin-top: 24px; padding: 20px; background-color: #0b1528; border-left: 4px solid #38bdf8; border-radius: 8px;">
|
|
<h4 style="margin: 0 0 10px 0; color: #94a3b8; font-size: 13px; text-transform: uppercase; letter-spacing: 0.05em;">Notes / Message:</h4>
|
|
<p style="margin: 0; color: #f1f5f9; font-size: 15px; line-height: 1.6; white-space: pre-line;">${message}</p>
|
|
</div>
|
|
` : ''}
|
|
</div>
|
|
|
|
<div style="text-align: center; padding-top: 20px; border-top: 1px solid #334155; color: #64748b; font-size: 12px;">
|
|
Submitted on ${new Date().toLocaleString()} from Cavin Infotech Careers Form
|
|
</div>
|
|
</div>
|
|
`;
|
|
|
|
// Auto-reply HTML (sent to the applicant)
|
|
const autoReplyHtml = `
|
|
<div style="font-family: 'Segoe UI', Helvetica, Arial, sans-serif; background-color: #020710; color: #f8fafc; padding: 40px 20px; max-width: 650px; margin: 0 auto; border-radius: 16px; border: 1px solid #1e293b;">
|
|
<div style="text-align: center; padding-bottom: 24px; border-bottom: 1px solid #334155;">
|
|
<h2 style="color: #38bdf8; font-size: 24px; margin: 0; font-weight: 700;">Cavin Infotech</h2>
|
|
<p style="color: #94a3b8; font-size: 14px; margin-top: 6px;">Application Received — Thank You!</p>
|
|
</div>
|
|
|
|
<div style="padding: 28px 0;">
|
|
<p style="font-size: 16px; color: #e2e8f0; line-height: 1.7; margin: 0 0 16px 0;">
|
|
Dear <strong style="color: #ffffff;">${name}</strong>,
|
|
</p>
|
|
<p style="font-size: 15px; color: #cbd5e1; line-height: 1.7; margin: 0 0 16px 0;">
|
|
Thank you for applying to <strong style="color: #38bdf8;">Cavin Infotech</strong>. We have successfully received your application and resume.
|
|
</p>
|
|
<p style="font-size: 15px; color: #cbd5e1; line-height: 1.7; margin: 0 0 24px 0;">
|
|
Our team will review your profile and reach out to you if your qualifications match our current openings. We appreciate your interest in joining our team!
|
|
</p>
|
|
|
|
<div style="background: linear-gradient(135deg, rgba(3, 135, 218, 0.15) 0%, rgba(2, 7, 16, 0.6) 100%); border: 1px solid rgba(56, 189, 248, 0.2); border-radius: 12px; padding: 20px 24px; margin-bottom: 24px;">
|
|
<p style="margin: 0 0 8px 0; font-size: 13px; color: #94a3b8; text-transform: uppercase; letter-spacing: 0.05em;">Application Summary</p>
|
|
<p style="margin: 4px 0; font-size: 14px; color: #e2e8f0;"><strong style="color: #38bdf8;">Name:</strong> ${name}</p>
|
|
<p style="margin: 4px 0; font-size: 14px; color: #e2e8f0;"><strong style="color: #38bdf8;">Email:</strong> ${email}</p>
|
|
<p style="margin: 4px 0; font-size: 14px; color: #e2e8f0;"><strong style="color: #38bdf8;">Phone:</strong> ${phone || 'Not provided'}</p>
|
|
<p style="margin: 4px 0; font-size: 14px; color: #e2e8f0;"><strong style="color: #38bdf8;">Resume:</strong> ${resumeName || 'Submitted'}</p>
|
|
</div>
|
|
|
|
<p style="font-size: 13px; color: #64748b; line-height: 1.6; margin: 0;">
|
|
This is an automated confirmation email. Please do not reply to this message. For enquiries, contact us at
|
|
<a href="mailto:info@cavinfotech.com" style="color: #38bdf8; text-decoration: none;">info@cavinfotech.com</a>.
|
|
</p>
|
|
</div>
|
|
|
|
<div style="text-align: center; padding-top: 20px; border-top: 1px solid #334155; color: #64748b; font-size: 12px;">
|
|
© ${new Date().getFullYear()} Cavin Infotech. All rights reserved.
|
|
</div>
|
|
</div>
|
|
`;
|
|
|
|
if (!transporter) {
|
|
return {
|
|
success: false,
|
|
error: 'SMTP credentials not configured on the server. Please set SMTP_HOST, SMTP_USER, and SMTP_PASS in .env file.'
|
|
};
|
|
}
|
|
|
|
try {
|
|
// 1. Send internal team notification (with resume attachment)
|
|
const mailOptions = {
|
|
from: noReplyEmail,
|
|
to: toEmail,
|
|
replyTo: `"${name}" <${email}>`,
|
|
subject: mailSubject,
|
|
text: `New Careers Application:\nName: ${name}\nEmail: ${email}\nPhone: ${phone}\nResume: ${resumeName}`,
|
|
html: internalHtml
|
|
};
|
|
|
|
if (file) {
|
|
mailOptions.attachments = [
|
|
{
|
|
filename: file.originalname,
|
|
content: file.buffer
|
|
}
|
|
];
|
|
}
|
|
|
|
const info = await transporter.sendMail(mailOptions);
|
|
|
|
// 2. Send auto-reply confirmation to the applicant
|
|
await transporter.sendMail({
|
|
from: noReplyEmail,
|
|
to: email,
|
|
subject: `We've received your application — Cavin Infotech`,
|
|
text: `Dear ${name},\n\nThank you for applying to Cavin Infotech. We have received your application and will review it shortly.\n\nThis is an automated confirmation. Please do not reply to this email.\n\n© ${new Date().getFullYear()} Cavin Infotech`,
|
|
html: autoReplyHtml
|
|
});
|
|
|
|
return { success: true, messageId: info.messageId };
|
|
} catch (err) {
|
|
return { success: false, error: err.message || 'SMTP sending failed' };
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sends a Strategy Call booking email via SMTP using nodemailer.
|
|
*/
|
|
export async function sendStrategyEmail({ name, email, phone, designation, dateTime, interests, message }) {
|
|
const transporter = createSmtpTransporter();
|
|
|
|
const toEmail = process.env.SMTP_TO || process.env.SMTP_USER || 'info@cavinfotech.com';
|
|
const fromEmail = process.env.SMTP_FROM || `"Cavin Infotech Strategy Call" <${process.env.SMTP_USER || 'info@cavinfotech.com'}>`;
|
|
|
|
const mailSubject = `[Strategy Call Booking] New Session Request from ${name}`;
|
|
|
|
const htmlContent = `
|
|
<div style="font-family: 'Segoe UI', Helvetica, Arial, sans-serif; background-color: #020710; color: #f8fafc; padding: 40px 20px; max-width: 650px; margin: 0 auto; border-radius: 16px; border: 1px solid #1e293b;">
|
|
<div style="text-align: center; padding-bottom: 24px; border-bottom: 1px solid #334155;">
|
|
<h2 style="color: #38bdf8; font-size: 24px; margin: 0; font-weight: 700;">Cavin Infotech</h2>
|
|
<p style="color: #94a3b8; font-size: 14px; margin-top: 6px;">New Strategy Call Session Request</p>
|
|
</div>
|
|
|
|
<div style="padding: 24px 0;">
|
|
<table style="width: 100%; border-collapse: collapse; color: #e2e8f0; font-size: 15px;">
|
|
<tr>
|
|
<td style="padding: 10px 0; font-weight: 600; color: #38bdf8; width: 160px;">Client Name:</td>
|
|
<td style="padding: 10px 0; color: #ffffff;">${name}</td>
|
|
</tr>
|
|
<tr>
|
|
<td style="padding: 10px 0; font-weight: 600; color: #38bdf8;">Email:</td>
|
|
<td style="padding: 10px 0;"><a href="mailto:${email}" style="color: #38bdf8; text-decoration: none;">${email}</a></td>
|
|
</tr>
|
|
<tr>
|
|
<td style="padding: 10px 0; font-weight: 600; color: #38bdf8;">Mobile:</td>
|
|
<td style="padding: 10px 0; color: #ffffff;">${phone || 'Not provided'}</td>
|
|
</tr>
|
|
<tr>
|
|
<td style="padding: 10px 0; font-weight: 600; color: #38bdf8;">Designation:</td>
|
|
<td style="padding: 10px 0; color: #ffffff;">${designation || 'Not provided'}</td>
|
|
</tr>
|
|
<tr>
|
|
<td style="padding: 10px 0; font-weight: 600; color: #38bdf8;">Preferred Slot:</td>
|
|
<td style="padding: 10px 0; color: #ffaa00; font-weight: 600;">${dateTime || 'Flexible'}</td>
|
|
</tr>
|
|
<tr>
|
|
<td style="padding: 10px 0; font-weight: 600; color: #38bdf8;">Areas of Interest:</td>
|
|
<td style="padding: 10px 0; color: #ffffff;">${interests || 'General Consultation'}</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
|
|
<div style="text-align: center; padding-top: 20px; border-top: 1px solid #334155; color: #64748b; font-size: 12px;">
|
|
Submitted on ${new Date().toLocaleString()} from Cavin Infotech Book a Strategy Call Modal
|
|
</div>
|
|
</div>
|
|
`;
|
|
|
|
if (!transporter) {
|
|
return {
|
|
success: false,
|
|
error: 'SMTP credentials not configured on the server. Please set SMTP_HOST, SMTP_USER, and SMTP_PASS in .env file.'
|
|
};
|
|
}
|
|
|
|
try {
|
|
const info = await transporter.sendMail({
|
|
from: fromEmail,
|
|
to: toEmail,
|
|
replyTo: `"${name}" <${email}>`,
|
|
subject: mailSubject,
|
|
text: `New Strategy Call Request:\nName: ${name}\nEmail: ${email}\nMobile: ${phone}\nDesignation: ${designation}\nPreferred Slot: ${dateTime}\nInterests: ${interests}`,
|
|
html: htmlContent
|
|
});
|
|
return { success: true, messageId: info.messageId };
|
|
} catch (err) {
|
|
return { success: false, error: err.message || 'SMTP sending failed' };
|
|
}
|
|
}
|