const emailService = require('../services/email'); const nocoDB = require('../services/nocodb'); const crypto = require('crypto'); class EmailsController { async sendEmail(req, res, next) { try { const { recipientEmail, senderName, senderEmail, subject, message, postalCode, recipientName } = req.body; // Send the email using template system const emailResult = await emailService.sendRepresentativeEmail( recipientEmail, senderName, senderEmail, subject, message, postalCode, recipientName ); // Log the email send event await nocoDB.logEmailSend({ recipientEmail, senderName, senderEmail, subject, message, postalCode, status: emailResult.success ? 'sent' : 'failed', timestamp: new Date().toISOString(), senderIP: req.ip || req.connection.remoteAddress }); if (emailResult.success) { res.json({ success: true, message: 'Email sent successfully', messageId: emailResult.messageId }); } else { res.status(500).json({ success: false, error: 'Failed to send email', message: emailResult.error }); } } catch (error) { console.error('Send email error:', error); res.status(500).json({ success: false, error: 'Failed to send email', message: error.message }); } } async previewEmail(req, res, next) { try { const { recipientEmail, subject, message, senderName, senderEmail, postalCode, recipientName } = req.body; const templateVariables = { MESSAGE: message, SENDER_NAME: senderName || 'Anonymous', SENDER_EMAIL: senderEmail || 'unknown@example.com', POSTAL_CODE: postalCode || 'Unknown', RECIPIENT_NAME: recipientName || 'Representative' }; const emailOptions = { to: recipientEmail, from: { email: process.env.SMTP_FROM_EMAIL, name: process.env.SMTP_FROM_NAME }, replyTo: senderEmail || process.env.SMTP_FROM_EMAIL, subject: subject }; const preview = await emailService.previewTemplatedEmail('representative-contact', templateVariables, emailOptions); // Log the email preview event (non-blocking) try { await nocoDB.logEmailPreview({ recipientEmail, senderName, senderEmail, subject, message, postalCode, timestamp: new Date().toISOString(), senderIP: req.ip || req.connection.remoteAddress }); } catch (loggingError) { console.error('Failed to log email preview:', loggingError); // Don't fail the preview if logging fails } res.json({ success: true, preview: preview, html: emailOptions.html }); } catch (error) { console.error('Email preview error:', error); res.status(500).json({ success: false, error: 'Failed to generate email preview', message: error.message }); } } async sendTestEmail(req, res, next) { try { const { subject, message } = req.body; const testRecipient = process.env.TEST_EMAIL_RECIPIENT || req.user?.email || 'admin@example.com'; const emailResult = await emailService.sendTestEmail(subject, message, testRecipient); if (emailResult.success) { res.json({ success: true, message: 'Test email sent successfully', messageId: emailResult.messageId, sentTo: testRecipient, testMode: emailResult.testMode }); } else { res.status(500).json({ success: false, error: 'Failed to send test email', message: emailResult.error }); } } catch (error) { console.error('Send test email error:', error); res.status(500).json({ success: false, error: 'Failed to send test email', message: error.message }); } } async getEmailLogs(req, res, next) { try { const { status, senderEmail, postalCode } = req.query; if (!process.env.NOCODB_TABLE_EMAILS) { return res.status(500).json({ success: false, error: 'Email logging not configured' }); } const filters = {}; if (status) filters.status = status; if (senderEmail) filters.senderEmail = senderEmail; if (postalCode) filters.postalCode = postalCode; const logs = await nocoDB.getEmailLogs(filters); res.json({ success: true, logs: logs || [] }); } catch (error) { console.error('Get email logs error:', error); res.status(500).json({ success: false, error: 'Failed to retrieve email logs', message: error.message }); } } async testSMTPConnection(req, res, next) { try { const testResult = await emailService.testConnection(); res.json({ success: testResult.success, message: testResult.message, error: testResult.error }); } catch (error) { console.error('SMTP test error:', error); res.status(500).json({ success: false, error: 'Failed to test SMTP connection', message: error.message }); } } async testSMTPConnection(req, res, next) { try { const result = await emailService.testConnection(); res.json({ success: result.success, message: result.message, error: result.error }); } catch (error) { console.error('SMTP test error:', error); res.status(500).json({ success: false, error: 'Failed to test SMTP connection', message: error.message }); } } async initiateEmailToCampaign(req, res, next) { try { const { email, subject, message, postalCode, senderName } = req.body; // Check if email verification is enabled const verificationEnabled = process.env.EMAIL_VERIFICATION_ENABLED !== 'false'; if (!verificationEnabled) { return res.status(400).json({ success: false, error: 'Email verification is not enabled' }); } // Generate verification token const token = crypto.randomBytes(32).toString('hex'); const expiryHours = parseInt(process.env.EMAIL_VERIFICATION_EXPIRY) || 24; const expiresAt = new Date(Date.now() + expiryHours * 60 * 60 * 1000); // Store token and campaign data await nocoDB.createEmailVerification({ token, email, temp_campaign_data: JSON.stringify({ subject, message, postalCode, senderName }), created_at: new Date().toISOString(), expires_at: expiresAt.toISOString(), used: false }); // Send verification email const appUrl = process.env.APP_URL || 'http://localhost:3333'; const verificationUrl = `${appUrl}/verify-email.html?token=${token}`; await emailService.sendEmailVerification(email, verificationUrl, senderName || 'there'); res.json({ success: true, message: 'Verification email sent. Please check your inbox.' }); } catch (error) { console.error('Email to campaign conversion error:', error); res.status(500).json({ success: false, error: 'Failed to initiate campaign conversion', message: error.message }); } } async verifyEmailToken(req, res, next) { try { const { token } = req.params; // Find verification record const verification = await nocoDB.getEmailVerificationByToken(token); if (!verification) { return res.status(404).json({ success: false, error: 'Invalid or expired verification link' }); } // Check if already used if (verification.used) { return res.status(400).json({ success: false, error: 'This verification link has already been used' }); } // Check if expired const now = new Date(); const expiresAt = new Date(verification.expires_at || verification.expiresAt || verification['Expires At']); if (now > expiresAt) { return res.status(400).json({ success: false, error: 'This verification link has expired' }); } // Mark as used const verificationId = verification.id || verification.Id || verification.ID; await nocoDB.updateEmailVerification(verificationId, { used: true }); // Parse campaign data const campaignDataStr = verification.temp_campaign_data || verification.tempCampaignData || verification['Temp Campaign Data']; const campaignData = JSON.parse(campaignDataStr); // Check if user exists const userEmail = verification.email || verification.Email; const existingUser = await nocoDB.getUserByEmail(userEmail); if (existingUser) { // User exists, log them in automatically req.session.authenticated = true; req.session.userId = existingUser.ID || existingUser.Id || existingUser.id; req.session.userEmail = existingUser.Email || existingUser.email; req.session.userName = existingUser.Name || existingUser.name; req.session.isAdmin = existingUser.Admin || existingUser.admin || false; req.session.userType = existingUser['User Type'] || existingUser.UserType || existingUser.userType || 'user'; req.session.save((err) => { if (err) { console.error('Session save error:', err); return res.status(500).json({ success: false, error: 'Session error' }); } res.json({ success: true, needsAccount: false, campaignData: campaignData, redirectTo: '/dashboard.html' }); }); } else { // User doesn't exist - create a new user account automatically try { // Generate a temporary password (user can change it later) const tempPassword = crypto.randomBytes(16).toString('hex'); // Extract name from campaign data or use email prefix const userName = campaignData.senderName || userEmail.split('@')[0]; // Create new user const newUser = await nocoDB.createUser({ 'Name': userName, 'Email': userEmail, 'Password': tempPassword, 'Admin': false, 'User Type': 'user' }); const userId = newUser.ID || newUser.Id || newUser.id || newUser; // Send login credentials email to the new user try { await emailService.sendLoginDetails({ Name: userName, Email: userEmail, Password: tempPassword, admin: false }); console.log('Welcome email with credentials sent to:', userEmail); } catch (emailError) { console.error('Failed to send welcome email:', emailError); // Don't fail the whole process if email sending fails } // Log the new user in automatically req.session.authenticated = true; req.session.userId = userId; req.session.userEmail = userEmail; req.session.userName = userName; req.session.isAdmin = false; req.session.userType = 'user'; req.session.save((err) => { if (err) { console.error('Session save error:', err); return res.status(500).json({ success: false, error: 'Session error' }); } res.json({ success: true, needsAccount: false, isNewUser: true, campaignData: campaignData, redirectTo: '/dashboard.html', message: 'Account created successfully! Check your email for login credentials.' }); }); } catch (createError) { console.error('Error creating user account:', createError); return res.status(500).json({ success: false, error: 'Failed to create user account', message: createError.message }); } } } catch (error) { console.error('Email verification error:', error); res.status(500).json({ success: false, error: 'Failed to verify email', message: error.message }); } } } module.exports = new EmailsController();