const { simpleParser } = require('mailparser'); const db = require('./db'); const emitter = require('./eventEmitter'); // Helper function to convert stream to buffer function streamToBuffer(stream) { return new Promise((resolve, reject) => { const chunks = []; stream.on('data', (chunk) => chunks.push(chunk)); stream.on('error', reject); stream.on('end', () => resolve(Buffer.concat(chunks))); }); } async function saveEmail(stream) { try { // First, buffer the entire stream const emailBuffer = await streamToBuffer(stream); // Now, parse the buffered email content const parsed = await simpleParser(emailBuffer); const rawEmail = emailBuffer.toString(); const recipient = parsed.to ? parsed.to.text : 'undisclosed-recipients'; const sender = parsed.from ? parsed.from.text : 'unknown-sender'; const subject = parsed.subject || 'No Subject'; const body = parsed.text || (parsed.html || ''); const [result] = await db.execute( 'INSERT INTO emails (recipient, sender, subject, body, raw) VALUES (?, ?, ?, ?, ?)', [recipient, sender, subject, body, rawEmail] ); const newEmailId = result.insertId; console.log(`Email from <${sender}> to <${recipient}> saved with ID: ${newEmailId}`); if (parsed.attachments && parsed.attachments.length > 0) { for (const attachment of parsed.attachments) { await db.execute( 'INSERT INTO email_attachments (email_id, filename, content_type, content) VALUES (?, ?, ?, ?)', [newEmailId, attachment.filename, attachment.contentType, attachment.content] ); console.log(`Attachment ${attachment.filename} saved.`); } } // Emit an event with the new email's main information const [rows] = await db.execute('SELECT id, sender, recipient, subject, body, received_at FROM emails WHERE id = ?', [newEmailId]); if (rows.length > 0) { emitter.emit('newEmail', rows[0]); } } catch (error) { console.error('Failed to save email:', error); // We should not exit the process here, but maybe throw the error // so the caller (SMTPServer) can handle it. throw error; } } module.exports = { saveEmail };