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 test SMTP server', async () => { testServer = await startTestServer({ port: 2551, tlsEnabled: false, authRequired: false }); expect(testServer).toBeTruthy(); expect(testServer.port).toBeGreaterThan(0); }); tap.test('CCMD-11: Server capabilities discovery', async () => { // Test server capabilities which is what HELP provides info about smtpClient = createSmtpClient({ host: testServer.hostname, port: testServer.port, secure: false, connectionTimeout: 5000 }); console.log('Testing server capabilities discovery (HELP equivalent):\n'); // Send a test email to see server capabilities in action const testEmail = new Email({ from: 'sender@example.com', to: ['recipient@example.com'], subject: 'Capability test', text: 'Testing server capabilities' }); await smtpClient.sendMail(testEmail); console.log('Email sent successfully - server supports basic SMTP commands'); // Test different configurations to understand server behavior const capabilities = { basicSMTP: true, multiplRecipients: false, largeMessages: false, internationalDomains: false }; // Test multiple recipients try { const multiEmail = new Email({ from: 'sender@example.com', to: ['recipient1@example.com', 'recipient2@example.com', 'recipient3@example.com'], subject: 'Multi-recipient test', text: 'Testing multiple recipients' }); await smtpClient.sendMail(multiEmail); capabilities.multiplRecipients = true; console.log('✓ Server supports multiple recipients'); } catch (error) { console.log('✗ Multiple recipients not supported'); } console.log('\nDetected capabilities:', capabilities); }); tap.test('CCMD-11: Error message diagnostics', async () => { // Test error messages which HELP would explain console.log('Testing error message diagnostics:\n'); const errorTests = [ { description: 'Invalid sender address', email: { from: 'invalid-sender', to: ['recipient@example.com'], subject: 'Test', text: 'Test' } }, { description: 'Empty recipient list', email: { from: 'sender@example.com', to: [], subject: 'Test', text: 'Test' } }, { description: 'Null subject', email: { from: 'sender@example.com', to: ['recipient@example.com'], subject: null as any, text: 'Test' } } ]; for (const test of errorTests) { console.log(`Testing: ${test.description}`); try { const email = new Email(test.email); await smtpClient.sendMail(email); console.log(' Unexpectedly succeeded'); } catch (error) { console.log(` Error: ${error.message}`); console.log(` This would be explained in HELP documentation`); } console.log(''); } }); tap.test('CCMD-11: Connection configuration help', async () => { // Test different connection configurations console.log('Testing connection configurations:\n'); const configs = [ { name: 'Standard connection', config: { host: testServer.hostname, port: testServer.port, secure: false, connectionTimeout: 5000 }, shouldWork: true }, { name: 'With greeting timeout', config: { host: testServer.hostname, port: testServer.port, secure: false, connectionTimeout: 5000, greetingTimeout: 3000 }, shouldWork: true }, { name: 'With socket timeout', config: { host: testServer.hostname, port: testServer.port, secure: false, connectionTimeout: 5000, socketTimeout: 10000 }, shouldWork: true } ]; for (const testConfig of configs) { console.log(`Testing: ${testConfig.name}`); try { const client = createSmtpClient(testConfig.config); const email = new Email({ from: 'sender@example.com', to: ['recipient@example.com'], subject: 'Config test', text: `Testing ${testConfig.name}` }); await client.sendMail(email); console.log(` ✓ Configuration works`); } catch (error) { console.log(` ✗ Error: ${error.message}`); } } }); tap.test('CCMD-11: Protocol flow documentation', async () => { // Document the protocol flow (what HELP would explain) console.log('SMTP Protocol Flow (as HELP would document):\n'); const protocolSteps = [ '1. Connection established', '2. Server sends greeting (220)', '3. Client sends EHLO', '4. Server responds with capabilities', '5. Client sends MAIL FROM', '6. Server accepts sender (250)', '7. Client sends RCPT TO', '8. Server accepts recipient (250)', '9. Client sends DATA', '10. Server ready for data (354)', '11. Client sends message content', '12. Client sends . to end', '13. Server accepts message (250)', '14. Client can send more or QUIT' ]; console.log('Standard SMTP transaction flow:'); protocolSteps.forEach(step => console.log(` ${step}`)); // Demonstrate the flow console.log('\nDemonstrating flow with actual email:'); const email = new Email({ from: 'demo@example.com', to: ['recipient@example.com'], subject: 'Protocol flow demo', text: 'Demonstrating SMTP protocol flow' }); await smtpClient.sendMail(email); console.log('✓ Protocol flow completed successfully'); }); tap.test('CCMD-11: Command availability matrix', async () => { // Test what commands are available (HELP info) console.log('Testing command availability:\n'); // Test various email features to determine support const features = { plainText: { supported: false, description: 'Plain text emails' }, htmlContent: { supported: false, description: 'HTML emails' }, attachments: { supported: false, description: 'File attachments' }, multipleRecipients: { supported: false, description: 'Multiple recipients' }, ccRecipients: { supported: false, description: 'CC recipients' }, bccRecipients: { supported: false, description: 'BCC recipients' }, customHeaders: { supported: false, description: 'Custom headers' }, priorities: { supported: false, description: 'Email priorities' } }; // Test plain text try { await smtpClient.sendMail(new Email({ from: 'sender@example.com', to: ['recipient@example.com'], subject: 'Plain text test', text: 'Plain text content' })); features.plainText.supported = true; } catch (e) {} // Test HTML try { await smtpClient.sendMail(new Email({ from: 'sender@example.com', to: ['recipient@example.com'], subject: 'HTML test', html: '

HTML content

' })); features.htmlContent.supported = true; } catch (e) {} // Test multiple recipients try { await smtpClient.sendMail(new Email({ from: 'sender@example.com', to: ['recipient1@example.com', 'recipient2@example.com'], subject: 'Multiple recipients test', text: 'Test' })); features.multipleRecipients.supported = true; } catch (e) {} // Test CC try { await smtpClient.sendMail(new Email({ from: 'sender@example.com', to: ['recipient@example.com'], cc: ['cc@example.com'], subject: 'CC test', text: 'Test' })); features.ccRecipients.supported = true; } catch (e) {} // Test BCC try { await smtpClient.sendMail(new Email({ from: 'sender@example.com', to: ['recipient@example.com'], bcc: ['bcc@example.com'], subject: 'BCC test', text: 'Test' })); features.bccRecipients.supported = true; } catch (e) {} console.log('Feature support matrix:'); Object.entries(features).forEach(([key, value]) => { console.log(` ${value.description}: ${value.supported ? '✓ Supported' : '✗ Not supported'}`); }); }); tap.test('CCMD-11: Error code reference', async () => { // Document error codes (HELP would explain these) console.log('SMTP Error Code Reference (as HELP would provide):\n'); const errorCodes = [ { code: '220', meaning: 'Service ready', type: 'Success' }, { code: '221', meaning: 'Service closing transmission channel', type: 'Success' }, { code: '250', meaning: 'Requested action completed', type: 'Success' }, { code: '251', meaning: 'User not local; will forward', type: 'Success' }, { code: '354', meaning: 'Start mail input', type: 'Intermediate' }, { code: '421', meaning: 'Service not available', type: 'Temporary failure' }, { code: '450', meaning: 'Mailbox unavailable', type: 'Temporary failure' }, { code: '451', meaning: 'Local error in processing', type: 'Temporary failure' }, { code: '452', meaning: 'Insufficient storage', type: 'Temporary failure' }, { code: '500', meaning: 'Syntax error', type: 'Permanent failure' }, { code: '501', meaning: 'Syntax error in parameters', type: 'Permanent failure' }, { code: '502', meaning: 'Command not implemented', type: 'Permanent failure' }, { code: '503', meaning: 'Bad sequence of commands', type: 'Permanent failure' }, { code: '550', meaning: 'Mailbox not found', type: 'Permanent failure' }, { code: '551', meaning: 'User not local', type: 'Permanent failure' }, { code: '552', meaning: 'Storage allocation exceeded', type: 'Permanent failure' }, { code: '553', meaning: 'Mailbox name not allowed', type: 'Permanent failure' }, { code: '554', meaning: 'Transaction failed', type: 'Permanent failure' } ]; console.log('Common SMTP response codes:'); errorCodes.forEach(({ code, meaning, type }) => { console.log(` ${code} - ${meaning} (${type})`); }); // Test triggering some errors console.log('\nDemonstrating error handling:'); // Invalid email format try { await smtpClient.sendMail(new Email({ from: 'invalid-email-format', to: ['recipient@example.com'], subject: 'Test', text: 'Test' })); } catch (error) { console.log(`Invalid format error: ${error.message}`); } }); tap.test('CCMD-11: Debugging assistance', async () => { // Test debugging features (HELP assists with debugging) console.log('Debugging assistance features:\n'); // Create client with debug enabled const debugClient = createSmtpClient({ host: testServer.hostname, port: testServer.port, secure: false, connectionTimeout: 5000, debug: true }); console.log('Sending email with debug mode enabled:'); console.log('(Debug output would show full SMTP conversation)\n'); const debugEmail = new Email({ from: 'debug@example.com', to: ['recipient@example.com'], subject: 'Debug test', text: 'Testing with debug mode' }); // The debug output will be visible in the console await debugClient.sendMail(debugEmail); console.log('\nDebug mode helps troubleshoot:'); console.log('- Connection issues'); console.log('- Authentication problems'); console.log('- Message formatting errors'); console.log('- Server response codes'); console.log('- Protocol violations'); }); tap.test('CCMD-11: Performance benchmarks', async () => { // Performance info (HELP might mention performance tips) console.log('Performance benchmarks:\n'); const messageCount = 10; const startTime = Date.now(); for (let i = 0; i < messageCount; i++) { const email = new Email({ from: 'perf@example.com', to: ['recipient@example.com'], subject: `Performance test ${i + 1}`, text: 'Testing performance' }); await smtpClient.sendMail(email); } const totalTime = Date.now() - startTime; const avgTime = totalTime / messageCount; console.log(`Sent ${messageCount} emails in ${totalTime}ms`); console.log(`Average time per email: ${avgTime.toFixed(2)}ms`); console.log(`Throughput: ${(1000 / avgTime).toFixed(2)} emails/second`); console.log('\nPerformance tips:'); console.log('- Use connection pooling for multiple emails'); console.log('- Enable pipelining when supported'); console.log('- Batch recipients when possible'); console.log('- Use appropriate timeouts'); console.log('- Monitor connection limits'); }); tap.test('cleanup test SMTP server', async () => { if (testServer) { await stopTestServer(testServer); } }); export default tap.start();