dcrouter/test/suite/smtpclient_commands/test.ccmd-02.mail-from-parameters.ts
2025-05-26 04:09:29 +00:00

277 lines
8.0 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 MAIL FROM tests', async () => {
testServer = await startTestServer({
port: 2541,
tlsEnabled: false,
authRequired: false,
size: 10 * 1024 * 1024 // 10MB size limit
});
expect(testServer.port).toEqual(2541);
});
tap.test('setup - create SMTP client', async () => {
smtpClient = createSmtpClient({
host: testServer.hostname,
port: testServer.port,
secure: false,
connectionTimeout: 5000,
debug: true
});
const isConnected = await smtpClient.verify();
expect(isConnected).toBeTrue();
});
tap.test('CCMD-02: MAIL FROM - should send basic MAIL FROM command', async () => {
const email = new Email({
from: 'sender@example.com',
to: 'recipient@example.com',
subject: 'Basic MAIL FROM Test',
text: 'Testing basic MAIL FROM command'
});
const result = await smtpClient.sendMail(email);
expect(result.success).toBeTrue();
expect(result.envelope?.from).toEqual('sender@example.com');
console.log('✅ Basic MAIL FROM command sent successfully');
});
tap.test('CCMD-02: MAIL FROM - should handle display names correctly', async () => {
const email = new Email({
from: 'John Doe <john.doe@example.com>',
to: 'Jane Smith <jane.smith@example.com>',
subject: 'Display Name Test',
text: 'Testing MAIL FROM with display names'
});
const result = await smtpClient.sendMail(email);
expect(result.success).toBeTrue();
// Envelope should contain only email address, not display name
expect(result.envelope?.from).toEqual('john.doe@example.com');
console.log('✅ Display names handled correctly in MAIL FROM');
});
tap.test('CCMD-02: MAIL FROM - should handle SIZE parameter if server supports it', async () => {
// Send a larger email to test SIZE parameter
const largeContent = 'x'.repeat(1000000); // 1MB of content
const email = new Email({
from: 'sender@example.com',
to: 'recipient@example.com',
subject: 'SIZE Parameter Test',
text: largeContent
});
const result = await smtpClient.sendMail(email);
expect(result.success).toBeTrue();
console.log('✅ SIZE parameter handled for large email');
});
tap.test('CCMD-02: MAIL FROM - should handle international email addresses', async () => {
const email = new Email({
from: 'user@例え.jp',
to: 'recipient@example.com',
subject: 'International Domain Test',
text: 'Testing international domains in MAIL FROM'
});
try {
const result = await smtpClient.sendMail(email);
if (result.success) {
console.log('✅ International domain accepted');
expect(result.envelope?.from).toContain('@');
}
} catch (error) {
// Some servers may not support international domains
console.log(' Server does not support international domains');
}
});
tap.test('CCMD-02: MAIL FROM - should handle empty return path (bounce address)', async () => {
const email = new Email({
from: '<>', // Empty return path for bounces
to: 'recipient@example.com',
subject: 'Bounce Message Test',
text: 'This is a bounce message with empty return path'
});
try {
const result = await smtpClient.sendMail(email);
if (result.success) {
console.log('✅ Empty return path accepted for bounce');
expect(result.envelope?.from).toEqual('');
}
} catch (error) {
console.log(' Server rejected empty return path');
}
});
tap.test('CCMD-02: MAIL FROM - should handle special characters in local part', async () => {
const specialEmails = [
'user+tag@example.com',
'first.last@example.com',
'user_name@example.com',
'user-name@example.com'
];
for (const fromEmail of specialEmails) {
const email = new Email({
from: fromEmail,
to: 'recipient@example.com',
subject: 'Special Character Test',
text: `Testing special characters in: ${fromEmail}`
});
const result = await smtpClient.sendMail(email);
expect(result.success).toBeTrue();
expect(result.envelope?.from).toEqual(fromEmail);
console.log(`✅ Special character email accepted: ${fromEmail}`);
}
});
tap.test('CCMD-02: MAIL FROM - should reject invalid sender addresses', async () => {
const invalidSenders = [
'no-at-sign',
'@example.com',
'user@',
'user@@example.com',
'user@.com',
'user@example.',
'user with spaces@example.com'
];
let rejectedCount = 0;
for (const invalidSender of invalidSenders) {
try {
const email = new Email({
from: invalidSender,
to: 'recipient@example.com',
subject: 'Invalid Sender Test',
text: 'This should fail'
});
await smtpClient.sendMail(email);
} catch (error) {
rejectedCount++;
console.log(`✅ Invalid sender rejected: ${invalidSender}`);
}
}
expect(rejectedCount).toBeGreaterThan(0);
});
tap.test('CCMD-02: MAIL FROM - should handle 8BITMIME parameter', async () => {
const email = new Email({
from: 'sender@example.com',
to: 'recipient@example.com',
subject: 'UTF-8 Test with special characters',
text: 'This email contains UTF-8 characters: 你好世界 🌍',
html: '<p>UTF-8 content: <strong>你好世界</strong> 🌍</p>'
});
const result = await smtpClient.sendMail(email);
expect(result.success).toBeTrue();
console.log('✅ 8BITMIME content handled correctly');
});
tap.test('CCMD-02: MAIL FROM - should handle AUTH parameter if authenticated', async () => {
// Create authenticated client - auth requires TLS per RFC 8314
const authServer = await startTestServer({
port: 2542,
tlsEnabled: true,
authRequired: true
});
const authClient = createSmtpClient({
host: authServer.hostname,
port: authServer.port,
secure: false, // Use STARTTLS instead of direct TLS
requireTLS: true, // Require TLS upgrade
tls: {
rejectUnauthorized: false // Accept self-signed cert for testing
},
auth: {
user: 'testuser',
pass: 'testpass'
},
connectionTimeout: 5000,
debug: true
});
try {
const email = new Email({
from: 'authenticated@example.com',
to: 'recipient@example.com',
subject: 'AUTH Parameter Test',
text: 'Sent with authentication'
});
const result = await authClient.sendMail(email);
expect(result.success).toBeTrue();
console.log('✅ AUTH parameter handled in MAIL FROM');
} catch (error) {
console.error('AUTH test error:', error);
throw error;
} finally {
await authClient.close();
await stopTestServer(authServer);
}
});
tap.test('CCMD-02: MAIL FROM - should handle very long email addresses', async () => {
// RFC allows up to 320 characters total (64 + @ + 255)
const longLocal = 'a'.repeat(64);
const longDomain = 'subdomain.' + 'a'.repeat(60) + '.example.com';
const longEmail = `${longLocal}@${longDomain}`;
const email = new Email({
from: longEmail,
to: 'recipient@example.com',
subject: 'Long Email Address Test',
text: 'Testing maximum length email addresses'
});
try {
const result = await smtpClient.sendMail(email);
if (result.success) {
console.log('✅ Long email address accepted');
expect(result.envelope?.from).toEqual(longEmail);
}
} catch (error) {
console.log(' Server enforces email length limits');
}
});
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();