dcrouter/test/suite/smtpclient_commands/test.ccmd-04.data-transmission.ts
2025-05-25 19:05:43 +00:00

274 lines
8.3 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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>
<head>
<title>HTML Email Test</title>
</head>
<body>
<h1>HTML Email</h1>
<p>This is an <strong>HTML</strong> email with:</p>
<ul>
<li>Lists</li>
<li>Formatting</li>
<li>Links: <a href="https://example.com">Example</a></li>
</ul>
</body>
</html>
`
});
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: '<p>Unicode: 你好世界 🌍 🚀 ✉️</p>'
});
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);
});
export default tap.start();