import nodemailer from 'nodemailer';
import { getCredentialsFromSession, decryptCredentials } from '~/server/utils/encryption';
import { uploadFile } from '~/server/utils/minio';
import { updateInterest } from '~/server/utils/nocodb';
export default defineEventHandler(async (event) => {
const xTagHeader = getRequestHeader(event, "x-tag");
if (!xTagHeader || (xTagHeader !== "094ut234" && xTagHeader !== "pjnvü1230")) {
throw createError({ statusCode: 401, statusMessage: "unauthenticated" });
}
try {
const body = await readBody(event);
const {
to,
subject,
body: emailBody,
interestId,
sessionId,
includeSignature = true,
signatureConfig
} = body;
if (!to || !subject || !emailBody || !sessionId) {
throw createError({
statusCode: 400,
statusMessage: "To, subject, body, and sessionId are required"
});
}
// Get encrypted credentials from session
const encryptedCredentials = getCredentialsFromSession(sessionId);
if (!encryptedCredentials) {
throw createError({
statusCode: 401,
statusMessage: "Email credentials not found. Please reconnect."
});
}
// Decrypt credentials
const { email, password } = decryptCredentials(encryptedCredentials);
// Get user info for signature
const defaultName = email.split('@')[0].replace('.', ' ').replace(/\b\w/g, l => l.toUpperCase());
// Build email signature with customizable fields
const sig = signatureConfig || {};
const contactLines = sig.contactInfo ? sig.contactInfo.split('\n').filter((line: string) => line.trim()).join('
') : '';
const signature = includeSignature ? `
${sig.name || defaultName}
${sig.title || 'Sales & Marketing Director'}
${sig.company || 'Port Nimara'}
${contactLines ? contactLines + '
' : ''}
${sig.email || email}
The information in this message is confidential and may be privileged.
It is intended for the addressee alone.
If you are not the intended recipient it is prohibited to disclose, use or copy this information.
Please contact the Sender immediately should this message have been transmitted incorrectly.
` : '';
// Convert plain text body to HTML with line breaks
const htmlBody = emailBody.replace(/\n/g, '
') + signature;
// Configure SMTP transport
const transporter = nodemailer.createTransport({
host: process.env.NUXT_EMAIL_SMTP_HOST || 'mail.portnimara.com',
port: parseInt(process.env.NUXT_EMAIL_SMTP_PORT || '587'),
secure: false, // false for STARTTLS
auth: {
user: email,
pass: password
},
tls: {
rejectUnauthorized: false // Allow self-signed certificates
}
});
// Send email
const fromName = sig.name || defaultName;
const info = await transporter.sendMail({
from: `"${fromName}" <${email}>`,
to: to,
subject: subject,
text: emailBody, // Plain text version
html: htmlBody // HTML version with signature
});
// Store email in MinIO for thread history and update EOI Time Sent
if (interestId) {
try {
const emailData = {
id: info.messageId,
from: email,
to: to,
subject: subject,
body: emailBody,
html: htmlBody,
timestamp: new Date().toISOString(),
direction: 'sent',
interestId: interestId
};
const objectName = `interest-${interestId}/${Date.now()}-sent.json`;
const buffer = Buffer.from(JSON.stringify(emailData, null, 2));
// Upload to the client-emails bucket
const { getMinioClient } = await import('~/server/utils/minio');
const client = getMinioClient();
await client.putObject('client-emails', objectName, buffer, buffer.length, {
'Content-Type': 'application/json',
});
// Update EOI Time Sent if the email contains an EOI link
if (emailBody.includes('signatures.portnimara.dev/sign/')) {
try {
await updateInterest(interestId, {
'EOI Time Sent': new Date().toISOString()
});
} catch (updateError) {
console.error('Failed to update EOI Time Sent:', updateError);
// Continue even if update fails
}
}
} catch (storageError) {
console.error('Failed to store email in MinIO:', storageError);
// Continue even if storage fails
}
}
return {
success: true,
message: "Email sent successfully",
messageId: info.messageId
};
} catch (error) {
console.error('Failed to send email:', error);
if (error instanceof Error) {
throw createError({
statusCode: 500,
statusMessage: `Failed to send email: ${error.message}`
});
} else {
throw createError({
statusCode: 500,
statusMessage: "An unexpected error occurred",
});
}
}
});