166 lines
5.8 KiB
TypeScript
166 lines
5.8 KiB
TypeScript
import nodemailer from 'nodemailer';
|
|
import Imap from 'imap';
|
|
import { encryptCredentials, storeCredentialsInSession } from '~/server/utils/encryption';
|
|
|
|
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 { email, password, imapHost, smtpHost, sessionId } = body;
|
|
|
|
console.log('[test-connection] Testing email connection for:', email);
|
|
|
|
if (!email || !password || !sessionId) {
|
|
throw createError({
|
|
statusCode: 400,
|
|
statusMessage: "Email, password, and sessionId are required"
|
|
});
|
|
}
|
|
|
|
// Use provided hosts or defaults from environment
|
|
const imapHostToUse = imapHost || process.env.NUXT_EMAIL_IMAP_HOST || 'mail.portnimara.com';
|
|
const smtpHostToUse = smtpHost || process.env.NUXT_EMAIL_SMTP_HOST || 'mail.portnimara.com';
|
|
const imapPort = parseInt(process.env.NUXT_EMAIL_IMAP_PORT || '993');
|
|
const smtpPort = parseInt(process.env.NUXT_EMAIL_SMTP_PORT || '587');
|
|
|
|
console.log('[test-connection] Using IMAP:', imapHostToUse, ':', imapPort);
|
|
console.log('[test-connection] Using SMTP:', smtpHostToUse, ':', smtpPort);
|
|
|
|
// Test SMTP connection
|
|
console.log('[test-connection] Testing SMTP connection...');
|
|
const transporter = nodemailer.createTransport({
|
|
host: smtpHostToUse,
|
|
port: smtpPort,
|
|
secure: false, // false for STARTTLS
|
|
auth: {
|
|
user: email,
|
|
pass: password
|
|
},
|
|
tls: {
|
|
rejectUnauthorized: false // Allow self-signed certificates
|
|
}
|
|
});
|
|
|
|
try {
|
|
await transporter.verify();
|
|
console.log('[test-connection] SMTP connection successful');
|
|
} catch (smtpError: any) {
|
|
console.error('[test-connection] SMTP connection failed:', smtpError);
|
|
throw new Error(`SMTP connection failed: ${smtpError.message || smtpError}`);
|
|
}
|
|
|
|
// Test IMAP connection
|
|
const imapConfig = {
|
|
user: email,
|
|
password: password,
|
|
host: imapHostToUse,
|
|
port: imapPort,
|
|
tls: true,
|
|
tlsOptions: {
|
|
rejectUnauthorized: false // Allow self-signed certificates
|
|
}
|
|
};
|
|
|
|
const testImapConnection = (retryCount = 0): Promise<boolean> => {
|
|
return new Promise((resolve, reject) => {
|
|
console.log(`[test-connection] Testing IMAP connection... (Attempt ${retryCount + 1}/3)`);
|
|
const imap = new Imap(imapConfig);
|
|
|
|
// Add a timeout to prevent hanging
|
|
const timeout = setTimeout(() => {
|
|
console.error('[test-connection] IMAP connection timeout');
|
|
imap.end();
|
|
|
|
// Retry on timeout if we haven't exceeded max retries
|
|
if (retryCount < 2) {
|
|
console.log('[test-connection] Retrying IMAP connection after timeout...');
|
|
setTimeout(() => {
|
|
testImapConnection(retryCount + 1)
|
|
.then(resolve)
|
|
.catch(reject);
|
|
}, (retryCount + 1) * 1000); // Exponential backoff
|
|
} else {
|
|
reject(new Error('IMAP connection timeout after 15 seconds and 3 attempts'));
|
|
}
|
|
}, 15000); // 15 second timeout per attempt
|
|
|
|
imap.once('ready', () => {
|
|
console.log('[test-connection] IMAP connection successful');
|
|
clearTimeout(timeout);
|
|
imap.end();
|
|
resolve(true);
|
|
});
|
|
|
|
imap.once('error', (err: Error) => {
|
|
console.error('[test-connection] IMAP connection error:', err);
|
|
clearTimeout(timeout);
|
|
|
|
// Retry on certain errors if we haven't exceeded max retries
|
|
const shouldRetry = retryCount < 2 && (
|
|
err.message.includes('ECONNRESET') ||
|
|
err.message.includes('ETIMEDOUT') ||
|
|
err.message.includes('ENOTFOUND') ||
|
|
err.message.includes('socket hang up')
|
|
);
|
|
|
|
if (shouldRetry) {
|
|
console.log(`[test-connection] Retrying IMAP connection after error: ${err.message}`);
|
|
setTimeout(() => {
|
|
testImapConnection(retryCount + 1)
|
|
.then(resolve)
|
|
.catch(reject);
|
|
}, (retryCount + 1) * 1000); // Exponential backoff
|
|
} else {
|
|
reject(err);
|
|
}
|
|
});
|
|
|
|
imap.connect();
|
|
});
|
|
};
|
|
|
|
try {
|
|
await testImapConnection();
|
|
} catch (imapError: any) {
|
|
console.error('[test-connection] IMAP connection failed after all retries:', imapError);
|
|
throw new Error(`IMAP connection failed: ${imapError.message || imapError}`);
|
|
}
|
|
|
|
// If both connections successful, encrypt and store credentials
|
|
console.log('[test-connection] Both connections successful, storing credentials');
|
|
const encryptedCredentials = encryptCredentials(email, password);
|
|
storeCredentialsInSession(sessionId, encryptedCredentials);
|
|
|
|
return {
|
|
success: true,
|
|
message: "Email connection tested successfully",
|
|
email: email
|
|
};
|
|
} catch (error) {
|
|
console.error('Email connection test failed:', error);
|
|
if (error instanceof Error) {
|
|
// Check for common authentication errors
|
|
if (error.message.includes('Authentication') || error.message.includes('AUTHENTICATIONFAILED')) {
|
|
throw createError({
|
|
statusCode: 401,
|
|
statusMessage: "Invalid email or password"
|
|
});
|
|
}
|
|
throw createError({
|
|
statusCode: 500,
|
|
statusMessage: `Connection failed: ${error.message}`
|
|
});
|
|
} else {
|
|
throw createError({
|
|
statusCode: 500,
|
|
statusMessage: "An unexpected error occurred",
|
|
});
|
|
}
|
|
}
|
|
});
|