import { tap, expect } from '@git.zone/tstest/tapbundle'; import { startTestServer, stopTestServer, type ITestServer } from '../../helpers/server.loader.js'; import { createSmtpClient } from '../../../ts/mail/delivery/smtpclient/index.js'; import { Email } from '../../../ts/mail/core/classes.email.js'; import * as net from 'net'; let testServer: ITestServer; tap.test('setup - start SMTP server for size limit tests', async () => { testServer = await startTestServer({ port: 2573, tlsEnabled: false, authRequired: false }); expect(testServer.port).toEqual(2573); }); tap.test('CERR-07: Server with SIZE extension', async () => { // Create server that advertises SIZE extension const sizeServer = net.createServer((socket) => { socket.write('220 Size Test Server\r\n'); let buffer = ''; let inData = false; socket.on('data', (data) => { buffer += data.toString(); let lines = buffer.split('\r\n'); buffer = lines.pop() || ''; for (const line of lines) { const command = line.trim(); if (!command) continue; if (inData) { if (command === '.') { inData = false; socket.write('250 OK\r\n'); } continue; } if (command.startsWith('EHLO')) { socket.write('250-SIZE 1048576\r\n'); // 1MB limit socket.write('250 OK\r\n'); } else if (command.startsWith('MAIL FROM')) { socket.write('250 OK\r\n'); } else if (command.startsWith('RCPT TO')) { socket.write('250 OK\r\n'); } else if (command === 'DATA') { socket.write('354 Send data\r\n'); inData = true; } else if (command === 'QUIT') { socket.write('221 Bye\r\n'); socket.end(); } } }); }); await new Promise((resolve) => { sizeServer.listen(2574, () => resolve()); }); const smtpClient = await createSmtpClient({ host: '127.0.0.1', port: 2574, secure: false, connectionTimeout: 5000 }); const email = new Email({ from: 'sender@example.com', to: 'recipient@example.com', subject: 'Size Test', text: 'Testing SIZE extension' }); const result = await smtpClient.sendMail(email); expect(result.success).toBeTrue(); console.log('✅ Email sent with SIZE extension support'); await smtpClient.close(); await new Promise((resolve) => { sizeServer.close(() => resolve()); }); }); tap.test('CERR-07: Message too large at MAIL FROM', async () => { // Create server that rejects based on SIZE parameter const strictSizeServer = net.createServer((socket) => { socket.write('220 Strict Size Server\r\n'); socket.on('data', (data) => { const command = data.toString().trim(); if (command.startsWith('EHLO')) { socket.write('250-SIZE 1000\r\n'); // Very small limit socket.write('250 OK\r\n'); } else if (command.startsWith('MAIL FROM')) { // Always reject with size error socket.write('552 5.3.4 Message size exceeds fixed maximum message size\r\n'); } else if (command === 'QUIT') { socket.write('221 Bye\r\n'); socket.end(); } }); }); await new Promise((resolve) => { strictSizeServer.listen(2575, () => resolve()); }); const smtpClient = await createSmtpClient({ host: '127.0.0.1', port: 2575, secure: false, connectionTimeout: 5000 }); const email = new Email({ from: 'sender@example.com', to: 'recipient@example.com', subject: 'Large Message', text: 'This message will be rejected due to size' }); const result = await smtpClient.sendMail(email); expect(result.success).toBeFalse(); console.log('Actual error:', result.error?.message); expect(result.error?.message).toMatch(/552|size|exceeds|maximum/i); console.log('✅ Message size rejection at MAIL FROM handled'); await smtpClient.close(); await new Promise((resolve) => { strictSizeServer.close(() => resolve()); }); }); tap.test('CERR-07: Message too large at DATA', async () => { // Create server that rejects after receiving data const dataRejectServer = net.createServer((socket) => { socket.write('220 Data Reject Server\r\n'); let buffer = ''; let inData = false; socket.on('data', (data) => { buffer += data.toString(); let lines = buffer.split('\r\n'); buffer = lines.pop() || ''; for (const line of lines) { const command = line.trim(); if (!command) continue; if (inData) { if (command === '.') { inData = false; socket.write('552 5.3.4 Message too big for system\r\n'); } continue; } if (command.startsWith('EHLO')) { socket.write('250 OK\r\n'); } else if (command.startsWith('MAIL FROM')) { socket.write('250 OK\r\n'); } else if (command.startsWith('RCPT TO')) { socket.write('250 OK\r\n'); } else if (command === 'DATA') { socket.write('354 Send data\r\n'); inData = true; } else if (command === 'QUIT') { socket.write('221 Bye\r\n'); socket.end(); } } }); }); await new Promise((resolve) => { dataRejectServer.listen(2576, () => resolve()); }); const smtpClient = await createSmtpClient({ host: '127.0.0.1', port: 2576, secure: false, connectionTimeout: 5000 }); const email = new Email({ from: 'sender@example.com', to: 'recipient@example.com', subject: 'Large Message Test', text: 'x'.repeat(10000) // Simulate large content }); const result = await smtpClient.sendMail(email); expect(result.success).toBeFalse(); console.log('Actual error:', result.error?.message); expect(result.error?.message).toMatch(/552|big|size|data/i); console.log('✅ Message size rejection at DATA handled'); await smtpClient.close(); await new Promise((resolve) => { dataRejectServer.close(() => resolve()); }); }); tap.test('CERR-07: Temporary size error - 452', async () => { // Create server that returns temporary size error const tempSizeServer = net.createServer((socket) => { socket.write('220 Temp Size Server\r\n'); let buffer = ''; let inData = false; socket.on('data', (data) => { buffer += data.toString(); let lines = buffer.split('\r\n'); buffer = lines.pop() || ''; for (const line of lines) { const command = line.trim(); if (!command) continue; if (inData) { if (command === '.') { inData = false; socket.write('452 4.3.1 Insufficient system storage\r\n'); } continue; } if (command.startsWith('EHLO')) { socket.write('250 OK\r\n'); } else if (command.startsWith('MAIL FROM')) { socket.write('250 OK\r\n'); } else if (command.startsWith('RCPT TO')) { socket.write('250 OK\r\n'); } else if (command === 'DATA') { socket.write('354 Send data\r\n'); inData = true; } else if (command === 'QUIT') { socket.write('221 Bye\r\n'); socket.end(); } } }); }); await new Promise((resolve) => { tempSizeServer.listen(2577, () => resolve()); }); const smtpClient = await createSmtpClient({ host: '127.0.0.1', port: 2577, secure: false, connectionTimeout: 5000 }); const email = new Email({ from: 'sender@example.com', to: 'recipient@example.com', subject: 'Temporary Size Error Test', text: 'Testing temporary size error' }); const result = await smtpClient.sendMail(email); expect(result.success).toBeFalse(); console.log('Actual error:', result.error?.message); expect(result.error?.message).toMatch(/452|storage|data/i); console.log('✅ Temporary size error handled'); await smtpClient.close(); await new Promise((resolve) => { tempSizeServer.close(() => resolve()); }); }); tap.test('CERR-07: Normal email within size limits', async () => { // Test successful email send with working server const smtpClient = await createSmtpClient({ host: testServer.hostname, port: testServer.port, secure: false, connectionTimeout: 5000 }); const email = new Email({ from: 'sender@example.com', to: 'recipient@example.com', subject: 'Normal Size Test', text: 'Testing normal size email that should succeed' }); const result = await smtpClient.sendMail(email); expect(result.success).toBeTrue(); console.log('✅ Normal size email sent successfully'); await smtpClient.close(); }); tap.test('cleanup - stop SMTP server', async () => { await stopTestServer(testServer); }); export default tap.start();