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 type { SmtpClient } from '../../../ts/mail/delivery/smtpclient/smtp-client.js'; import { Email } from '../../../ts/mail/core/classes.email.js'; let testServer: ITestServer; let smtpClient: SmtpClient; tap.test('setup - start SMTP server for DATA command tests', async () => { testServer = await startTestServer({ port: 2544, tlsEnabled: false, authRequired: false, size: 10 * 1024 * 1024 // 10MB message size limit }); expect(testServer.port).toEqual(2544); }); tap.test('setup - create SMTP client', async () => { smtpClient = createSmtpClient({ host: testServer.hostname, port: testServer.port, secure: false, connectionTimeout: 5000, socketTimeout: 30000, // Longer timeout for data transmission debug: true }); const isConnected = await smtpClient.verify(); expect(isConnected).toBeTrue(); }); tap.test('CCMD-04: DATA - should transmit simple text email', async () => { const email = new Email({ from: 'sender@example.com', to: 'recipient@example.com', subject: 'Simple DATA Test', text: 'This is a simple text email transmitted via DATA command.' }); const result = await smtpClient.sendMail(email); expect(result.success).toBeTrue(); expect(result.response).toBeTypeofString(); console.log('✅ Simple text email transmitted successfully'); console.log('📧 Server response:', result.response); }); tap.test('CCMD-04: DATA - should handle dot stuffing', async () => { // Lines starting with dots should be escaped const email = new Email({ from: 'sender@example.com', to: 'recipient@example.com', subject: 'Dot Stuffing Test', text: 'This email tests dot stuffing:\n.This line starts with a dot\n..So does this one\n...And this one' }); const result = await smtpClient.sendMail(email); expect(result.success).toBeTrue(); console.log('✅ Dot stuffing handled correctly'); }); tap.test('CCMD-04: DATA - should transmit HTML email', async () => { const email = new Email({ from: 'sender@example.com', to: 'recipient@example.com', subject: 'HTML Email Test', text: 'This is the plain text version', html: ` HTML Email Test

HTML Email

This is an HTML email with:

` }); const result = await smtpClient.sendMail(email); expect(result.success).toBeTrue(); console.log('✅ HTML email transmitted successfully'); }); tap.test('CCMD-04: DATA - should handle large message body', async () => { // Create a large message (1MB) const largeText = 'This is a test line that will be repeated many times.\n'.repeat(20000); const email = new Email({ from: 'sender@example.com', to: 'recipient@example.com', subject: 'Large Message Test', text: largeText }); const startTime = Date.now(); const result = await smtpClient.sendMail(email); const duration = Date.now() - startTime; expect(result.success).toBeTrue(); console.log(`✅ Large message (${Math.round(largeText.length / 1024)}KB) transmitted in ${duration}ms`); }); tap.test('CCMD-04: DATA - should handle binary attachments', async () => { // Create a binary attachment const binaryData = Buffer.alloc(1024); for (let i = 0; i < binaryData.length; i++) { binaryData[i] = i % 256; } const email = new Email({ from: 'sender@example.com', to: 'recipient@example.com', subject: 'Binary Attachment Test', text: 'This email contains a binary attachment', attachments: [{ filename: 'test.bin', content: binaryData, contentType: 'application/octet-stream' }] }); const result = await smtpClient.sendMail(email); expect(result.success).toBeTrue(); console.log('✅ Binary attachment transmitted successfully'); }); tap.test('CCMD-04: DATA - should handle special characters and encoding', async () => { const email = new Email({ from: 'sender@example.com', to: 'recipient@example.com', subject: 'Special Characters Test – "Quotes" & More', text: 'Special characters: © ® ™ € £ ¥ • … « » " " ' '', html: '

Unicode: 你好世界 🌍 🚀 ✉️

' }); const result = await smtpClient.sendMail(email); expect(result.success).toBeTrue(); console.log('✅ Special characters and Unicode handled correctly'); }); tap.test('CCMD-04: DATA - should handle line length limits', async () => { // RFC 5321 specifies 1000 character line limit (including CRLF) const longLine = 'a'.repeat(990); // Leave room for CRLF and safety const email = new Email({ from: 'sender@example.com', to: 'recipient@example.com', subject: 'Long Line Test', text: `Short line\n${longLine}\nAnother short line` }); const result = await smtpClient.sendMail(email); expect(result.success).toBeTrue(); console.log('✅ Long lines handled within RFC limits'); }); tap.test('CCMD-04: DATA - should handle empty message body', async () => { const email = new Email({ from: 'sender@example.com', to: 'recipient@example.com', subject: 'Empty Body Test', text: '' // Empty body }); const result = await smtpClient.sendMail(email); expect(result.success).toBeTrue(); console.log('✅ Empty message body handled correctly'); }); tap.test('CCMD-04: DATA - should handle CRLF line endings', async () => { const email = new Email({ from: 'sender@example.com', to: 'recipient@example.com', subject: 'CRLF Test', text: 'Line 1\r\nLine 2\r\nLine 3\nLine 4 (LF only)\r\nLine 5' }); const result = await smtpClient.sendMail(email); expect(result.success).toBeTrue(); console.log('✅ Mixed line endings normalized to CRLF'); }); tap.test('CCMD-04: DATA - should handle message headers correctly', async () => { const email = new Email({ from: 'sender@example.com', to: 'recipient@example.com', cc: 'cc@example.com', subject: 'Header Test', text: 'Testing header transmission', priority: 'high', headers: { 'X-Custom-Header': 'custom-value', 'X-Mailer': 'SMTP Client Test Suite', 'Reply-To': 'replies@example.com' } }); const result = await smtpClient.sendMail(email); expect(result.success).toBeTrue(); console.log('✅ All headers transmitted in DATA command'); }); tap.test('CCMD-04: DATA - should handle timeout for slow transmission', async () => { // Create a very large message to test timeout handling const hugeText = 'x'.repeat(5 * 1024 * 1024); // 5MB const email = new Email({ from: 'sender@example.com', to: 'recipient@example.com', subject: 'Timeout Test', text: hugeText }); // Should complete within socket timeout const startTime = Date.now(); const result = await smtpClient.sendMail(email); const duration = Date.now() - startTime; expect(result.success).toBeTrue(); expect(duration).toBeLessThan(30000); // Should complete within socket timeout console.log(`✅ Large data transmission completed in ${duration}ms`); }); tap.test('CCMD-04: DATA - should handle server rejection after DATA', async () => { // Some servers might reject after seeing content const email = new Email({ from: 'spam@spammer.com', to: 'recipient@example.com', subject: 'Potential Spam Test', text: 'BUY NOW! SPECIAL OFFER! CLICK HERE!', mightBeSpam: true // Flag as potential spam }); const result = await smtpClient.sendMail(email); // Test server might accept or reject if (result.success) { console.log('ℹ️ Test server accepted potential spam (normal for test)'); } else { console.log('✅ Server can reject messages after DATA inspection'); } }); tap.test('cleanup - close SMTP client', async () => { if (smtpClient && smtpClient.isConnected()) { await smtpClient.close(); } }); tap.test('cleanup - stop SMTP server', async () => { await stopTestServer(testServer); }); tap.start();