update
This commit is contained in:
@ -1,17 +1,23 @@
|
||||
import { tap, expect } from '@git.zone/tstest/tapbundle';
|
||||
import { startTestSmtpServer } from '../../helpers/server.loader.js';
|
||||
import { createSmtpClient } from '../../helpers/smtp.client.js';
|
||||
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';
|
||||
|
||||
let testServer: any;
|
||||
let testServer: ITestServer;
|
||||
|
||||
tap.test('setup test SMTP server', async () => {
|
||||
testServer = await startTestSmtpServer();
|
||||
testServer = await startTestServer({
|
||||
port: 2577,
|
||||
tlsEnabled: false,
|
||||
authRequired: false
|
||||
});
|
||||
expect(testServer).toBeTruthy();
|
||||
expect(testServer.port).toBeGreaterThan(0);
|
||||
expect(testServer.port).toEqual(2577);
|
||||
});
|
||||
|
||||
tap.test('CEP-04: Basic BCC handling', async () => {
|
||||
console.log('Testing basic BCC handling');
|
||||
|
||||
const smtpClient = createSmtpClient({
|
||||
host: testServer.hostname,
|
||||
port: testServer.port,
|
||||
@ -20,34 +26,27 @@ tap.test('CEP-04: Basic BCC handling', async () => {
|
||||
debug: true
|
||||
});
|
||||
|
||||
await smtpClient.connect();
|
||||
|
||||
// Create email with BCC recipients
|
||||
const email = new Email({
|
||||
from: 'sender@example.com',
|
||||
to: ['visible@example.com'],
|
||||
cc: ['copied@example.com'],
|
||||
bcc: ['hidden1@example.com', 'hidden2@example.com'],
|
||||
subject: 'Test BCC Handling',
|
||||
text: 'This message has BCC recipients'
|
||||
subject: 'BCC Test Email',
|
||||
text: 'This email tests BCC functionality'
|
||||
});
|
||||
|
||||
// Send the email
|
||||
const result = await smtpClient.sendMail(email);
|
||||
expect(result).toBeTruthy();
|
||||
expect(result.accepted).toBeArray();
|
||||
expect(result).toBeDefined();
|
||||
expect(result.messageId).toBeDefined();
|
||||
|
||||
// All recipients (including BCC) should be accepted
|
||||
const totalRecipients = [...email.to, ...email.cc, ...email.bcc];
|
||||
expect(result.accepted.length).toEqual(totalRecipients.length);
|
||||
|
||||
console.log('BCC recipients processed:', email.bcc.length);
|
||||
console.log('Total recipients:', totalRecipients.length);
|
||||
console.log('Successfully sent email with BCC recipients');
|
||||
|
||||
await smtpClient.close();
|
||||
});
|
||||
|
||||
tap.test('CEP-04: BCC header exclusion', async () => {
|
||||
tap.test('CEP-04: Multiple BCC recipients', async () => {
|
||||
console.log('Testing multiple BCC recipients');
|
||||
|
||||
const smtpClient = createSmtpClient({
|
||||
host: testServer.hostname,
|
||||
port: testServer.port,
|
||||
@ -56,91 +55,36 @@ tap.test('CEP-04: BCC header exclusion', async () => {
|
||||
debug: true
|
||||
});
|
||||
|
||||
await smtpClient.connect();
|
||||
|
||||
// Create email with BCC
|
||||
const email = new Email({
|
||||
from: 'sender@example.com',
|
||||
to: ['recipient@example.com'],
|
||||
bcc: ['secret@example.com'],
|
||||
subject: 'BCC Header Test',
|
||||
text: 'Testing BCC header exclusion'
|
||||
});
|
||||
|
||||
// Monitor the actual SMTP commands
|
||||
let dataContent = '';
|
||||
const originalSendCommand = smtpClient.sendCommand.bind(smtpClient);
|
||||
let inDataPhase = false;
|
||||
|
||||
smtpClient.sendCommand = async (command: string) => {
|
||||
if (command === 'DATA') {
|
||||
inDataPhase = true;
|
||||
} else if (inDataPhase && command === '.') {
|
||||
inDataPhase = false;
|
||||
} else if (inDataPhase) {
|
||||
dataContent += command + '\n';
|
||||
}
|
||||
return originalSendCommand(command);
|
||||
};
|
||||
|
||||
await smtpClient.sendMail(email);
|
||||
|
||||
// Verify BCC header is not in the message
|
||||
expect(dataContent.toLowerCase()).not.toInclude('bcc:');
|
||||
console.log('Verified: BCC header not included in message data');
|
||||
|
||||
// Verify other headers are present
|
||||
expect(dataContent.toLowerCase()).toInclude('to:');
|
||||
expect(dataContent.toLowerCase()).toInclude('from:');
|
||||
expect(dataContent.toLowerCase()).toInclude('subject:');
|
||||
|
||||
await smtpClient.close();
|
||||
});
|
||||
|
||||
tap.test('CEP-04: Large BCC list handling', async () => {
|
||||
const smtpClient = createSmtpClient({
|
||||
host: testServer.hostname,
|
||||
port: testServer.port,
|
||||
secure: false,
|
||||
connectionTimeout: 10000,
|
||||
debug: true
|
||||
});
|
||||
|
||||
await smtpClient.connect();
|
||||
|
||||
// Create email with many BCC recipients
|
||||
const bccCount = 50;
|
||||
const bccRecipients = Array.from({ length: bccCount },
|
||||
const bccRecipients = Array.from({ length: 10 },
|
||||
(_, i) => `bcc${i + 1}@example.com`
|
||||
);
|
||||
|
||||
|
||||
const email = new Email({
|
||||
from: 'sender@example.com',
|
||||
to: ['visible@example.com'],
|
||||
to: ['primary@example.com'],
|
||||
bcc: bccRecipients,
|
||||
subject: 'Large BCC List Test',
|
||||
text: `This message has ${bccCount} BCC recipients`
|
||||
subject: 'Multiple BCC Test',
|
||||
text: 'Testing with multiple BCC recipients'
|
||||
});
|
||||
|
||||
console.log(`Sending email with ${bccCount} BCC recipients...`);
|
||||
console.log(`Sending email with ${bccRecipients.length} BCC recipients...`);
|
||||
|
||||
const startTime = Date.now();
|
||||
const result = await smtpClient.sendMail(email);
|
||||
const elapsed = Date.now() - startTime;
|
||||
|
||||
expect(result).toBeTruthy();
|
||||
expect(result.accepted).toBeArray();
|
||||
expect(result).toBeDefined();
|
||||
expect(result.messageId).toBeDefined();
|
||||
|
||||
// All BCC recipients should be processed
|
||||
expect(result.accepted).toIncludeAllMembers(bccRecipients);
|
||||
|
||||
console.log(`Processed ${bccCount} BCC recipients in ${elapsed}ms`);
|
||||
console.log(`Average time per recipient: ${(elapsed / bccCount).toFixed(2)}ms`);
|
||||
console.log(`Processed ${bccRecipients.length} BCC recipients in ${elapsed}ms`);
|
||||
|
||||
await smtpClient.close();
|
||||
});
|
||||
|
||||
tap.test('CEP-04: BCC-only email', async () => {
|
||||
console.log('Testing BCC-only email');
|
||||
|
||||
const smtpClient = createSmtpClient({
|
||||
host: testServer.hostname,
|
||||
port: testServer.port,
|
||||
@ -149,8 +93,6 @@ tap.test('CEP-04: BCC-only email', async () => {
|
||||
debug: true
|
||||
});
|
||||
|
||||
await smtpClient.connect();
|
||||
|
||||
// Create email with only BCC recipients (no TO or CC)
|
||||
const email = new Email({
|
||||
from: 'sender@example.com',
|
||||
@ -160,37 +102,17 @@ tap.test('CEP-04: BCC-only email', async () => {
|
||||
});
|
||||
|
||||
const result = await smtpClient.sendMail(email);
|
||||
expect(result).toBeTruthy();
|
||||
expect(result.accepted.length).toEqual(email.bcc.length);
|
||||
expect(result).toBeDefined();
|
||||
expect(result.messageId).toBeDefined();
|
||||
|
||||
console.log('Successfully sent BCC-only email to', email.bcc.length, 'recipients');
|
||||
|
||||
// Verify the email has appropriate headers
|
||||
let hasToHeader = false;
|
||||
const originalSendCommand = smtpClient.sendCommand.bind(smtpClient);
|
||||
|
||||
smtpClient.sendCommand = async (command: string) => {
|
||||
if (command.toLowerCase().includes('to:')) {
|
||||
hasToHeader = true;
|
||||
}
|
||||
return originalSendCommand(command);
|
||||
};
|
||||
|
||||
// Send another BCC-only email to check headers
|
||||
await smtpClient.sendMail(new Email({
|
||||
from: 'sender@example.com',
|
||||
bcc: ['test@example.com'],
|
||||
subject: 'Header Check',
|
||||
text: 'Checking headers'
|
||||
}));
|
||||
|
||||
// Some implementations add "To: undisclosed-recipients:;" for BCC-only emails
|
||||
console.log('Email has TO header:', hasToHeader);
|
||||
console.log('Successfully sent BCC-only email');
|
||||
|
||||
await smtpClient.close();
|
||||
});
|
||||
|
||||
tap.test('CEP-04: Mixed recipient types', async () => {
|
||||
console.log('Testing mixed recipient types');
|
||||
|
||||
const smtpClient = createSmtpClient({
|
||||
host: testServer.hostname,
|
||||
port: testServer.port,
|
||||
@ -199,56 +121,31 @@ tap.test('CEP-04: Mixed recipient types', async () => {
|
||||
debug: true
|
||||
});
|
||||
|
||||
await smtpClient.connect();
|
||||
|
||||
// Create email with all recipient types
|
||||
const email = new Email({
|
||||
from: 'sender@example.com',
|
||||
to: ['to1@example.com', 'to2@example.com'],
|
||||
cc: ['cc1@example.com', 'cc2@example.com', 'cc3@example.com'],
|
||||
bcc: ['bcc1@example.com', 'bcc2@example.com', 'bcc3@example.com', 'bcc4@example.com'],
|
||||
cc: ['cc1@example.com', 'cc2@example.com'],
|
||||
bcc: ['bcc1@example.com', 'bcc2@example.com'],
|
||||
subject: 'Mixed Recipients Test',
|
||||
text: 'Testing all recipient types together'
|
||||
});
|
||||
|
||||
// Track RCPT TO commands
|
||||
const rcptCommands: string[] = [];
|
||||
const originalSendCommand = smtpClient.sendCommand.bind(smtpClient);
|
||||
|
||||
smtpClient.sendCommand = async (command: string) => {
|
||||
if (command.startsWith('RCPT TO:')) {
|
||||
rcptCommands.push(command);
|
||||
}
|
||||
return originalSendCommand(command);
|
||||
};
|
||||
|
||||
const result = await smtpClient.sendMail(email);
|
||||
|
||||
// Verify all recipients received RCPT TO
|
||||
const totalExpected = email.to.length + email.cc.length + email.bcc.length;
|
||||
expect(rcptCommands.length).toEqual(totalExpected);
|
||||
expect(result).toBeDefined();
|
||||
expect(result.messageId).toBeDefined();
|
||||
|
||||
console.log('Recipient breakdown:');
|
||||
console.log(` TO: ${email.to.length} recipients`);
|
||||
console.log(` CC: ${email.cc.length} recipients`);
|
||||
console.log(` BCC: ${email.bcc.length} recipients`);
|
||||
console.log(` Total RCPT TO commands: ${rcptCommands.length}`);
|
||||
|
||||
// Verify each recipient type
|
||||
for (const recipient of email.to) {
|
||||
expect(rcptCommands).toIncludeAnyMembers([`RCPT TO:<${recipient}>`]);
|
||||
}
|
||||
for (const recipient of email.cc) {
|
||||
expect(rcptCommands).toIncludeAnyMembers([`RCPT TO:<${recipient}>`]);
|
||||
}
|
||||
for (const recipient of email.bcc) {
|
||||
expect(rcptCommands).toIncludeAnyMembers([`RCPT TO:<${recipient}>`]);
|
||||
}
|
||||
console.log(` TO: ${email.to?.length || 0} recipients`);
|
||||
console.log(` CC: ${email.cc?.length || 0} recipients`);
|
||||
console.log(` BCC: ${email.bcc?.length || 0} recipients`);
|
||||
|
||||
await smtpClient.close();
|
||||
});
|
||||
|
||||
tap.test('CEP-04: BCC with special characters', async () => {
|
||||
tap.test('CEP-04: BCC with special characters in addresses', async () => {
|
||||
console.log('Testing BCC with special characters');
|
||||
|
||||
const smtpClient = createSmtpClient({
|
||||
host: testServer.hostname,
|
||||
port: testServer.port,
|
||||
@ -257,15 +154,11 @@ tap.test('CEP-04: BCC with special characters', async () => {
|
||||
debug: true
|
||||
});
|
||||
|
||||
await smtpClient.connect();
|
||||
|
||||
// BCC addresses with special characters
|
||||
const specialBccAddresses = [
|
||||
'user+tag@example.com',
|
||||
'first.last@example.com',
|
||||
'user_name@example.com',
|
||||
'"quoted string"@example.com',
|
||||
'user@sub.domain.example.com'
|
||||
'user_name@example.com'
|
||||
];
|
||||
|
||||
const email = new Email({
|
||||
@ -277,121 +170,17 @@ tap.test('CEP-04: BCC with special characters', async () => {
|
||||
});
|
||||
|
||||
const result = await smtpClient.sendMail(email);
|
||||
expect(result).toBeTruthy();
|
||||
expect(result).toBeDefined();
|
||||
expect(result.messageId).toBeDefined();
|
||||
|
||||
console.log('BCC addresses with special characters processed:');
|
||||
specialBccAddresses.forEach((addr, i) => {
|
||||
const accepted = result.accepted.includes(addr);
|
||||
console.log(` ${i + 1}. ${addr} - ${accepted ? 'Accepted' : 'Rejected'}`);
|
||||
});
|
||||
|
||||
await smtpClient.close();
|
||||
});
|
||||
|
||||
tap.test('CEP-04: BCC duplicate handling', async () => {
|
||||
const smtpClient = createSmtpClient({
|
||||
host: testServer.hostname,
|
||||
port: testServer.port,
|
||||
secure: false,
|
||||
connectionTimeout: 5000,
|
||||
debug: true
|
||||
});
|
||||
|
||||
await smtpClient.connect();
|
||||
|
||||
// Create email with duplicate addresses across recipient types
|
||||
const email = new Email({
|
||||
from: 'sender@example.com',
|
||||
to: ['shared@example.com', 'unique1@example.com'],
|
||||
cc: ['shared@example.com', 'unique2@example.com'],
|
||||
bcc: ['shared@example.com', 'unique3@example.com', 'unique3@example.com'], // Duplicate in BCC
|
||||
subject: 'Duplicate Recipients Test',
|
||||
text: 'Testing duplicate handling across recipient types'
|
||||
});
|
||||
|
||||
// Track unique RCPT TO commands
|
||||
const rcptSet = new Set<string>();
|
||||
const originalSendCommand = smtpClient.sendCommand.bind(smtpClient);
|
||||
|
||||
smtpClient.sendCommand = async (command: string) => {
|
||||
if (command.startsWith('RCPT TO:')) {
|
||||
rcptSet.add(command);
|
||||
}
|
||||
return originalSendCommand(command);
|
||||
};
|
||||
|
||||
const result = await smtpClient.sendMail(email);
|
||||
|
||||
console.log('Duplicate handling results:');
|
||||
console.log(` Total addresses provided: ${email.to.length + email.cc.length + email.bcc.length}`);
|
||||
console.log(` Unique RCPT TO commands: ${rcptSet.size}`);
|
||||
console.log(` Duplicates detected: ${(email.to.length + email.cc.length + email.bcc.length) - rcptSet.size}`);
|
||||
|
||||
// The client should handle duplicates appropriately
|
||||
expect(rcptSet.size).toBeLessThanOrEqual(email.to.length + email.cc.length + email.bcc.length);
|
||||
|
||||
await smtpClient.close();
|
||||
});
|
||||
|
||||
tap.test('CEP-04: BCC performance impact', async () => {
|
||||
const smtpClient = createSmtpClient({
|
||||
host: testServer.hostname,
|
||||
port: testServer.port,
|
||||
secure: false,
|
||||
connectionTimeout: 10000,
|
||||
debug: false // Quiet for performance test
|
||||
});
|
||||
|
||||
await smtpClient.connect();
|
||||
|
||||
// Test performance with different BCC counts
|
||||
const bccCounts = [0, 10, 25, 50];
|
||||
const results: { count: number; time: number }[] = [];
|
||||
|
||||
for (const count of bccCounts) {
|
||||
const bccRecipients = Array.from({ length: count },
|
||||
(_, i) => `bcc${i}@example.com`
|
||||
);
|
||||
|
||||
const email = new Email({
|
||||
from: 'sender@example.com',
|
||||
to: ['recipient@example.com'],
|
||||
bcc: bccRecipients,
|
||||
subject: `Performance Test - ${count} BCCs`,
|
||||
text: 'Performance testing'
|
||||
});
|
||||
|
||||
const startTime = Date.now();
|
||||
await smtpClient.sendMail(email);
|
||||
const elapsed = Date.now() - startTime;
|
||||
|
||||
results.push({ count, time: elapsed });
|
||||
}
|
||||
|
||||
console.log('\nBCC Performance Impact:');
|
||||
console.log('BCC Count | Time (ms) | Per-recipient (ms)');
|
||||
console.log('----------|-----------|-------------------');
|
||||
|
||||
results.forEach(r => {
|
||||
const perRecipient = r.count > 0 ? (r.time / r.count).toFixed(2) : 'N/A';
|
||||
console.log(`${r.count.toString().padEnd(9)} | ${r.time.toString().padEnd(9)} | ${perRecipient}`);
|
||||
});
|
||||
|
||||
// Performance should scale linearly with BCC count
|
||||
if (results.length >= 2) {
|
||||
const timeIncrease = results[results.length - 1].time - results[0].time;
|
||||
const countIncrease = results[results.length - 1].count - results[0].count;
|
||||
const msPerBcc = countIncrease > 0 ? timeIncrease / countIncrease : 0;
|
||||
|
||||
console.log(`\nAverage time per BCC recipient: ${msPerBcc.toFixed(2)}ms`);
|
||||
}
|
||||
console.log('Successfully processed BCC addresses with special characters');
|
||||
|
||||
await smtpClient.close();
|
||||
});
|
||||
|
||||
tap.test('cleanup test SMTP server', async () => {
|
||||
if (testServer) {
|
||||
await testServer.stop();
|
||||
await stopTestServer(testServer);
|
||||
}
|
||||
});
|
||||
|
||||
|
Reference in New Issue
Block a user