import { requireAuth } from '~/server/utils/auth'; import nodemailer from 'nodemailer'; import Imap from 'imap'; import { encryptCredentials, storeCredentialsInSession } from '~/server/utils/encryption'; export default defineEventHandler(async (event) => { // Check authentication (x-tag header OR Keycloak session) await requireAuth(event); 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 => { 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", }); } } });