import { tap, expect } from '@push.rocks/tapbundle'; import * as plugins from '../plugins.js'; import * as net from 'net'; import { startTestServer, stopTestServer, TEST_PORT, sendEmailWithRawSocket } from '../server.loader.js'; let testServer: any; tap.test('setup - start test server', async () => { testServer = await startTestServer(); await plugins.smartdelay.delayFor(1000); }); tap.test('Bounce Management - Invalid recipient domain', async (tools) => { const done = tools.defer(); const socket = net.createConnection({ host: 'localhost', port: TEST_PORT, timeout: 30000 }); let dataBuffer = ''; let step = 'greeting'; socket.on('data', (data) => { dataBuffer += data.toString(); console.log('Server response:', data.toString()); if (step === 'greeting' && dataBuffer.includes('220 ')) { step = 'ehlo'; socket.write('EHLO testclient\r\n'); dataBuffer = ''; } else if (step === 'ehlo' && dataBuffer.includes('250')) { step = 'mail'; socket.write('MAIL FROM:\r\n'); dataBuffer = ''; } else if (step === 'mail' && dataBuffer.includes('250')) { step = 'rcpt'; // Send to non-existent domain socket.write('RCPT TO:\r\n'); dataBuffer = ''; } else if (step === 'rcpt') { if (dataBuffer.includes('550') || dataBuffer.includes('551') || dataBuffer.includes('553')) { console.log('Bounce management active - invalid recipient properly rejected'); expect(true).toBeTrue(); socket.write('QUIT\r\n'); socket.end(); done.resolve(); } else if (dataBuffer.includes('250')) { // Server accepted, may generate bounce later console.log('Invalid recipient accepted - bounce may be generated later'); step = 'data'; socket.write('DATA\r\n'); dataBuffer = ''; } } else if (step === 'data' && dataBuffer.includes('354')) { const email = [ `From: sender@example.com`, `To: nonexistent@invalid-domain-that-does-not-exist.com`, `Subject: Bounce Management Test`, `Return-Path: `, `Date: ${new Date().toUTCString()}`, `Message-ID: `, '', 'This email is designed to test bounce management functionality.', '.', '' ].join('\r\n'); socket.write(email); dataBuffer = ''; } else if (dataBuffer.includes('250 ') && dataBuffer.includes('Message accepted')) { console.log('Email accepted for processing - bounce will be generated'); expect(true).toBeTrue(); socket.write('QUIT\r\n'); socket.end(); done.resolve(); } }); socket.on('error', (err) => { console.error('Socket error:', err); done.reject(err); }); await done.promise; }); tap.test('Bounce Management - Empty return path (null sender)', async (tools) => { const done = tools.defer(); const socket = net.createConnection({ host: 'localhost', port: TEST_PORT, timeout: 30000 }); let dataBuffer = ''; let step = 'greeting'; socket.on('data', (data) => { dataBuffer += data.toString(); console.log('Server response:', data.toString()); if (step === 'greeting' && dataBuffer.includes('220 ')) { step = 'ehlo'; socket.write('EHLO testclient\r\n'); dataBuffer = ''; } else if (step === 'ehlo' && dataBuffer.includes('250')) { step = 'mail'; // Empty return path (null sender) - used for bounce messages socket.write('MAIL FROM:<>\r\n'); dataBuffer = ''; } else if (step === 'mail') { if (dataBuffer.includes('250')) { console.log('Null sender accepted (for bounce messages)'); step = 'rcpt'; socket.write('RCPT TO:\r\n'); dataBuffer = ''; } else { console.log('Null sender rejected'); expect(true).toBeTrue(); socket.write('QUIT\r\n'); socket.end(); done.resolve(); } } else if (step === 'rcpt' && dataBuffer.includes('250')) { step = 'data'; socket.write('DATA\r\n'); dataBuffer = ''; } else if (step === 'data' && dataBuffer.includes('354')) { // Bounce message format const email = [ `From: MAILER-DAEMON@example.com`, `To: recipient@example.com`, `Subject: Mail delivery failed: returning message to sender`, `Date: ${new Date().toUTCString()}`, `Message-ID: `, `Auto-Submitted: auto-replied`, '', 'This message was created automatically by mail delivery software.', '', 'A message that you sent could not be delivered to one or more recipients.', '.', '' ].join('\r\n'); socket.write(email); dataBuffer = ''; } else if (dataBuffer.includes('250 ') && dataBuffer.includes('Message accepted')) { console.log('Bounce message with null sender accepted'); expect(true).toBeTrue(); socket.write('QUIT\r\n'); socket.end(); done.resolve(); } }); socket.on('error', (err) => { console.error('Socket error:', err); done.reject(err); }); await done.promise; }); tap.test('Bounce Management - DSN headers', async (tools) => { const done = tools.defer(); const socket = net.createConnection({ host: 'localhost', port: TEST_PORT, timeout: 30000 }); let dataBuffer = ''; let step = 'greeting'; socket.on('data', (data) => { dataBuffer += data.toString(); console.log('Server response:', data.toString()); if (step === 'greeting' && dataBuffer.includes('220 ')) { step = 'ehlo'; socket.write('EHLO testclient\r\n'); dataBuffer = ''; } else if (step === 'ehlo' && dataBuffer.includes('250')) { step = 'mail'; socket.write('MAIL FROM:\r\n'); dataBuffer = ''; } else if (step === 'mail' && dataBuffer.includes('250')) { step = 'rcpt'; socket.write('RCPT TO:\r\n'); dataBuffer = ''; } else if (step === 'rcpt' && dataBuffer.includes('250')) { step = 'data'; socket.write('DATA\r\n'); dataBuffer = ''; } else if (step === 'data' && dataBuffer.includes('354')) { // Email with DSN request headers const email = [ `From: sender@example.com`, `To: recipient@example.com`, `Subject: DSN Test`, `Return-Path: `, `Disposition-Notification-To: sender@example.com`, `Return-Receipt-To: sender@example.com`, `Date: ${new Date().toUTCString()}`, `Message-ID: `, '', 'This email requests delivery status notifications.', '.', '' ].join('\r\n'); socket.write(email); dataBuffer = ''; } else if (dataBuffer.includes('250 ') && dataBuffer.includes('Message accepted')) { console.log('Email with DSN headers accepted'); expect(true).toBeTrue(); socket.write('QUIT\r\n'); socket.end(); done.resolve(); } }); socket.on('error', (err) => { console.error('Socket error:', err); done.reject(err); }); await done.promise; }); tap.test('Bounce Management - Bounce loop prevention', async (tools) => { const done = tools.defer(); const socket = net.createConnection({ host: 'localhost', port: TEST_PORT, timeout: 30000 }); let dataBuffer = ''; let step = 'greeting'; socket.on('data', (data) => { dataBuffer += data.toString(); console.log('Server response:', data.toString()); if (step === 'greeting' && dataBuffer.includes('220 ')) { step = 'ehlo'; socket.write('EHLO testclient\r\n'); dataBuffer = ''; } else if (step === 'ehlo' && dataBuffer.includes('250')) { step = 'mail'; // Null sender (bounce message) socket.write('MAIL FROM:<>\r\n'); dataBuffer = ''; } else if (step === 'mail' && dataBuffer.includes('250')) { step = 'rcpt'; // To another mailer-daemon (potential loop) socket.write('RCPT TO:\r\n'); dataBuffer = ''; } else if (step === 'rcpt') { if (dataBuffer.includes('550') || dataBuffer.includes('553')) { console.log('Bounce loop prevented - mailer-daemon recipient rejected'); expect(true).toBeTrue(); socket.write('QUIT\r\n'); socket.end(); done.resolve(); } else if (dataBuffer.includes('250')) { console.log('Mailer-daemon recipient accepted - check for loop prevention'); step = 'data'; socket.write('DATA\r\n'); dataBuffer = ''; } } else if (step === 'data' && dataBuffer.includes('354')) { const email = [ `From: MAILER-DAEMON@example.com`, `To: mailer-daemon@another-server.com`, `Subject: Delivery Status Notification (Failure)`, `Date: ${new Date().toUTCString()}`, `Message-ID: `, `Auto-Submitted: auto-replied`, `X-Loop: example.com`, '', 'This is a bounce of a bounce - potential loop.', '.', '' ].join('\r\n'); socket.write(email); dataBuffer = ''; } else if (dataBuffer.includes('250 ') || dataBuffer.includes('550 ')) { const result = dataBuffer.includes('250') ? 'accepted' : 'rejected'; console.log(`Bounce loop test: ${result}`); expect(true).toBeTrue(); socket.write('QUIT\r\n'); socket.end(); done.resolve(); } }); socket.on('error', (err) => { console.error('Socket error:', err); done.reject(err); }); await done.promise; }); tap.test('Bounce Management - Valid email (control test)', async (tools) => { const done = tools.defer(); const socket = net.createConnection({ host: 'localhost', port: TEST_PORT, timeout: 30000 }); let dataBuffer = ''; let step = 'greeting'; socket.on('data', (data) => { dataBuffer += data.toString(); console.log('Server response:', data.toString()); if (step === 'greeting' && dataBuffer.includes('220 ')) { step = 'ehlo'; socket.write('EHLO testclient\r\n'); dataBuffer = ''; } else if (step === 'ehlo' && dataBuffer.includes('250')) { step = 'mail'; socket.write('MAIL FROM:\r\n'); dataBuffer = ''; } else if (step === 'mail' && dataBuffer.includes('250')) { step = 'rcpt'; socket.write('RCPT TO:\r\n'); dataBuffer = ''; } else if (step === 'rcpt' && dataBuffer.includes('250')) { step = 'data'; socket.write('DATA\r\n'); dataBuffer = ''; } else if (step === 'data' && dataBuffer.includes('354')) { const email = [ `From: sender@example.com`, `To: valid@example.com`, `Subject: Valid Email Test`, `Return-Path: `, `Date: ${new Date().toUTCString()}`, `Message-ID: `, '', 'This is a valid email that should not trigger bounce.', '.', '' ].join('\r\n'); socket.write(email); dataBuffer = ''; } else if (dataBuffer.includes('250 ') && dataBuffer.includes('Message accepted')) { console.log('Valid email accepted - no bounce expected'); expect(true).toBeTrue(); socket.write('QUIT\r\n'); socket.end(); done.resolve(); } }); socket.on('error', (err) => { console.error('Socket error:', err); done.reject(err); }); await done.promise; }); tap.test('cleanup - stop test server', async () => { await stopTestServer(testServer); }); tap.start();