update
This commit is contained in:
@@ -1,27 +1,28 @@
|
||||
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: 2569,
|
||||
tlsEnabled: false,
|
||||
authRequired: false
|
||||
});
|
||||
expect(testServer).toBeTruthy();
|
||||
expect(testServer.port).toBeGreaterThan(0);
|
||||
expect(testServer.port).toEqual(2569);
|
||||
});
|
||||
|
||||
tap.test('CEP-09: Basic priority headers', async () => {
|
||||
const smtpClient = createSmtpClient({
|
||||
const smtpClient = await createSmtpClient({
|
||||
host: testServer.hostname,
|
||||
port: testServer.port,
|
||||
secure: false,
|
||||
connectionTimeout: 5000,
|
||||
debug: true
|
||||
connectionTimeout: 5000
|
||||
});
|
||||
|
||||
await smtpClient.connect();
|
||||
|
||||
// Test different priority levels
|
||||
const priorityLevels = [
|
||||
{ priority: 'high', headers: { 'X-Priority': '1', 'Importance': 'high' } },
|
||||
@@ -30,57 +31,35 @@ tap.test('CEP-09: Basic priority headers', async () => {
|
||||
];
|
||||
|
||||
for (const level of priorityLevels) {
|
||||
console.log(`\nTesting ${level.priority} priority email...`);
|
||||
console.log(`Testing ${level.priority} priority email...`);
|
||||
|
||||
const email = new Email({
|
||||
from: 'sender@example.com',
|
||||
to: ['recipient@example.com'],
|
||||
to: 'recipient@example.com',
|
||||
subject: `${level.priority.toUpperCase()} Priority Test`,
|
||||
text: `This is a ${level.priority} priority message`,
|
||||
priority: level.priority as 'high' | 'normal' | 'low'
|
||||
});
|
||||
|
||||
// Monitor headers
|
||||
const sentHeaders: { [key: string]: string } = {};
|
||||
const originalSendCommand = smtpClient.sendCommand.bind(smtpClient);
|
||||
|
||||
smtpClient.sendCommand = async (command: string) => {
|
||||
if (command.includes(':') && !command.startsWith('MAIL') && !command.startsWith('RCPT')) {
|
||||
const [key, value] = command.split(':').map(s => s.trim());
|
||||
if (key === 'X-Priority' || key === 'Importance' || key === 'X-MSMail-Priority') {
|
||||
sentHeaders[key] = value;
|
||||
}
|
||||
}
|
||||
return originalSendCommand(command);
|
||||
};
|
||||
|
||||
const result = await smtpClient.sendMail(email);
|
||||
expect(result).toBeTruthy();
|
||||
|
||||
console.log('Priority headers sent:');
|
||||
Object.entries(sentHeaders).forEach(([key, value]) => {
|
||||
console.log(` ${key}: ${value}`);
|
||||
});
|
||||
expect(result.success).toBeTruthy();
|
||||
}
|
||||
|
||||
await smtpClient.close();
|
||||
|
||||
console.log('Basic priority headers test completed successfully');
|
||||
});
|
||||
|
||||
tap.test('CEP-09: Multiple priority header formats', async () => {
|
||||
const smtpClient = createSmtpClient({
|
||||
const smtpClient = await createSmtpClient({
|
||||
host: testServer.hostname,
|
||||
port: testServer.port,
|
||||
secure: false,
|
||||
connectionTimeout: 5000,
|
||||
debug: true
|
||||
connectionTimeout: 5000
|
||||
});
|
||||
|
||||
await smtpClient.connect();
|
||||
|
||||
// Test various priority header combinations
|
||||
const email = new Email({
|
||||
from: 'sender@example.com',
|
||||
to: ['recipient@example.com'],
|
||||
to: 'recipient@example.com',
|
||||
subject: 'Multiple Priority Headers Test',
|
||||
text: 'Testing various priority header formats',
|
||||
headers: {
|
||||
@@ -92,95 +71,41 @@ tap.test('CEP-09: Multiple priority header formats', async () => {
|
||||
}
|
||||
});
|
||||
|
||||
// Capture all priority-related headers
|
||||
const priorityHeaders: string[] = [];
|
||||
const originalSendCommand = smtpClient.sendCommand.bind(smtpClient);
|
||||
|
||||
smtpClient.sendCommand = async (command: string) => {
|
||||
const priorityKeywords = ['priority', 'importance', 'urgent', 'flag'];
|
||||
if (command.includes(':') && priorityKeywords.some(kw => command.toLowerCase().includes(kw))) {
|
||||
priorityHeaders.push(command.trim());
|
||||
}
|
||||
return originalSendCommand(command);
|
||||
};
|
||||
|
||||
await smtpClient.sendMail(email);
|
||||
|
||||
console.log('\nAll priority-related headers:');
|
||||
priorityHeaders.forEach(header => {
|
||||
console.log(` ${header}`);
|
||||
});
|
||||
|
||||
await smtpClient.close();
|
||||
const result = await smtpClient.sendMail(email);
|
||||
expect(result.success).toBeTruthy();
|
||||
console.log('Multiple priority header formats test sent successfully');
|
||||
});
|
||||
|
||||
tap.test('CEP-09: Client-specific priority mappings', async () => {
|
||||
const smtpClient = createSmtpClient({
|
||||
const smtpClient = await createSmtpClient({
|
||||
host: testServer.hostname,
|
||||
port: testServer.port,
|
||||
secure: false,
|
||||
connectionTimeout: 5000,
|
||||
debug: true
|
||||
connectionTimeout: 5000
|
||||
});
|
||||
|
||||
await smtpClient.connect();
|
||||
|
||||
// Test how priority maps to different email clients
|
||||
const clientMappings = [
|
||||
{
|
||||
client: 'Outlook',
|
||||
high: { 'X-Priority': '1', 'X-MSMail-Priority': 'High', 'Importance': 'High' },
|
||||
normal: { 'X-Priority': '3', 'X-MSMail-Priority': 'Normal', 'Importance': 'Normal' },
|
||||
low: { 'X-Priority': '5', 'X-MSMail-Priority': 'Low', 'Importance': 'Low' }
|
||||
},
|
||||
{
|
||||
client: 'Thunderbird',
|
||||
high: { 'X-Priority': '1', 'Importance': 'High' },
|
||||
normal: { 'X-Priority': '3', 'Importance': 'Normal' },
|
||||
low: { 'X-Priority': '5', 'Importance': 'Low' }
|
||||
},
|
||||
{
|
||||
client: 'Apple Mail',
|
||||
high: { 'X-Priority': '1' },
|
||||
normal: { 'X-Priority': '3' },
|
||||
low: { 'X-Priority': '5' }
|
||||
}
|
||||
];
|
||||
|
||||
console.log('\nClient-specific priority header mappings:');
|
||||
|
||||
for (const mapping of clientMappings) {
|
||||
console.log(`\n${mapping.client}:`);
|
||||
console.log(' High priority:', JSON.stringify(mapping.high));
|
||||
console.log(' Normal priority:', JSON.stringify(mapping.normal));
|
||||
console.log(' Low priority:', JSON.stringify(mapping.low));
|
||||
}
|
||||
|
||||
// Send test email with comprehensive priority headers
|
||||
const email = new Email({
|
||||
from: 'sender@example.com',
|
||||
to: ['recipient@example.com'],
|
||||
to: 'recipient@example.com',
|
||||
subject: 'Cross-client Priority Test',
|
||||
text: 'This should appear as high priority in all clients',
|
||||
priority: 'high'
|
||||
});
|
||||
|
||||
await smtpClient.sendMail(email);
|
||||
|
||||
await smtpClient.close();
|
||||
const result = await smtpClient.sendMail(email);
|
||||
expect(result.success).toBeTruthy();
|
||||
console.log('Client-specific priority mappings test sent successfully');
|
||||
});
|
||||
|
||||
tap.test('CEP-09: Sensitivity and confidentiality headers', async () => {
|
||||
const smtpClient = createSmtpClient({
|
||||
const smtpClient = await createSmtpClient({
|
||||
host: testServer.hostname,
|
||||
port: testServer.port,
|
||||
secure: false,
|
||||
connectionTimeout: 5000,
|
||||
debug: true
|
||||
connectionTimeout: 5000
|
||||
});
|
||||
|
||||
await smtpClient.connect();
|
||||
|
||||
// Test sensitivity levels
|
||||
const sensitivityLevels = [
|
||||
{ level: 'Personal', description: 'Personal information' },
|
||||
@@ -192,7 +117,7 @@ tap.test('CEP-09: Sensitivity and confidentiality headers', async () => {
|
||||
for (const sensitivity of sensitivityLevels) {
|
||||
const email = new Email({
|
||||
from: 'sender@example.com',
|
||||
to: ['recipient@example.com'],
|
||||
to: 'recipient@example.com',
|
||||
subject: `${sensitivity.level} Message`,
|
||||
text: sensitivity.description,
|
||||
headers: {
|
||||
@@ -201,41 +126,25 @@ tap.test('CEP-09: Sensitivity and confidentiality headers', async () => {
|
||||
}
|
||||
});
|
||||
|
||||
// Monitor sensitivity headers
|
||||
let sensitivityHeader = '';
|
||||
const originalSendCommand = smtpClient.sendCommand.bind(smtpClient);
|
||||
|
||||
smtpClient.sendCommand = async (command: string) => {
|
||||
if (command.toLowerCase().includes('sensitivity:')) {
|
||||
sensitivityHeader = command.trim();
|
||||
}
|
||||
return originalSendCommand(command);
|
||||
};
|
||||
|
||||
await smtpClient.sendMail(email);
|
||||
|
||||
console.log(`\nSensitivity: ${sensitivity.level}`);
|
||||
console.log(` Header sent: ${sensitivityHeader}`);
|
||||
const result = await smtpClient.sendMail(email);
|
||||
expect(result.success).toBeTruthy();
|
||||
}
|
||||
|
||||
await smtpClient.close();
|
||||
|
||||
console.log('Sensitivity and confidentiality headers test completed successfully');
|
||||
});
|
||||
|
||||
tap.test('CEP-09: Auto-response suppression headers', async () => {
|
||||
const smtpClient = createSmtpClient({
|
||||
const smtpClient = await createSmtpClient({
|
||||
host: testServer.hostname,
|
||||
port: testServer.port,
|
||||
secure: false,
|
||||
connectionTimeout: 5000,
|
||||
debug: true
|
||||
connectionTimeout: 5000
|
||||
});
|
||||
|
||||
await smtpClient.connect();
|
||||
|
||||
// Headers to suppress auto-responses (vacation messages, etc.)
|
||||
const email = new Email({
|
||||
from: 'noreply@example.com',
|
||||
to: ['recipient@example.com'],
|
||||
to: 'recipient@example.com',
|
||||
subject: 'Automated Notification',
|
||||
text: 'This is an automated message. Please do not reply.',
|
||||
headers: {
|
||||
@@ -249,46 +158,26 @@ tap.test('CEP-09: Auto-response suppression headers', async () => {
|
||||
}
|
||||
});
|
||||
|
||||
// Capture auto-response suppression headers
|
||||
const suppressionHeaders: string[] = [];
|
||||
const originalSendCommand = smtpClient.sendCommand.bind(smtpClient);
|
||||
|
||||
smtpClient.sendCommand = async (command: string) => {
|
||||
const suppressionKeywords = ['auto', 'precedence', 'list-', 'bulk'];
|
||||
if (command.includes(':') && suppressionKeywords.some(kw => command.toLowerCase().includes(kw))) {
|
||||
suppressionHeaders.push(command.trim());
|
||||
}
|
||||
return originalSendCommand(command);
|
||||
};
|
||||
|
||||
await smtpClient.sendMail(email);
|
||||
|
||||
console.log('\nAuto-response suppression headers:');
|
||||
suppressionHeaders.forEach(header => {
|
||||
console.log(` ${header}`);
|
||||
});
|
||||
|
||||
await smtpClient.close();
|
||||
const result = await smtpClient.sendMail(email);
|
||||
expect(result.success).toBeTruthy();
|
||||
console.log('Auto-response suppression headers test sent successfully');
|
||||
});
|
||||
|
||||
tap.test('CEP-09: Expiration and retention headers', async () => {
|
||||
const smtpClient = createSmtpClient({
|
||||
const smtpClient = await createSmtpClient({
|
||||
host: testServer.hostname,
|
||||
port: testServer.port,
|
||||
secure: false,
|
||||
connectionTimeout: 5000,
|
||||
debug: true
|
||||
connectionTimeout: 5000
|
||||
});
|
||||
|
||||
await smtpClient.connect();
|
||||
|
||||
// Set expiration date for the email
|
||||
const expirationDate = new Date();
|
||||
expirationDate.setDate(expirationDate.getDate() + 7); // Expires in 7 days
|
||||
|
||||
const email = new Email({
|
||||
from: 'sender@example.com',
|
||||
to: ['recipient@example.com'],
|
||||
to: 'recipient@example.com',
|
||||
subject: 'Time-sensitive Information',
|
||||
text: 'This information expires in 7 days',
|
||||
headers: {
|
||||
@@ -299,42 +188,19 @@ tap.test('CEP-09: Expiration and retention headers', async () => {
|
||||
}
|
||||
});
|
||||
|
||||
// Monitor expiration headers
|
||||
const expirationHeaders: { [key: string]: string } = {};
|
||||
const originalSendCommand = smtpClient.sendCommand.bind(smtpClient);
|
||||
|
||||
smtpClient.sendCommand = async (command: string) => {
|
||||
if (command.includes(':')) {
|
||||
const [key, value] = command.split(':').map(s => s.trim());
|
||||
if (key.toLowerCase().includes('expir') || key.toLowerCase().includes('retention') ||
|
||||
key.toLowerCase().includes('ttl') || key.toLowerCase().includes('delete')) {
|
||||
expirationHeaders[key] = value;
|
||||
}
|
||||
}
|
||||
return originalSendCommand(command);
|
||||
};
|
||||
|
||||
await smtpClient.sendMail(email);
|
||||
|
||||
console.log('\nExpiration and retention headers:');
|
||||
Object.entries(expirationHeaders).forEach(([key, value]) => {
|
||||
console.log(` ${key}: ${value}`);
|
||||
});
|
||||
|
||||
await smtpClient.close();
|
||||
const result = await smtpClient.sendMail(email);
|
||||
expect(result.success).toBeTruthy();
|
||||
console.log('Expiration and retention headers test sent successfully');
|
||||
});
|
||||
|
||||
tap.test('CEP-09: Message flags and categories', async () => {
|
||||
const smtpClient = createSmtpClient({
|
||||
const smtpClient = await createSmtpClient({
|
||||
host: testServer.hostname,
|
||||
port: testServer.port,
|
||||
secure: false,
|
||||
connectionTimeout: 5000,
|
||||
debug: true
|
||||
connectionTimeout: 5000
|
||||
});
|
||||
|
||||
await smtpClient.connect();
|
||||
|
||||
// Test various message flags and categories
|
||||
const flaggedEmails = [
|
||||
{
|
||||
@@ -357,7 +223,7 @@ tap.test('CEP-09: Message flags and categories', async () => {
|
||||
for (const flaggedEmail of flaggedEmails) {
|
||||
const email = new Email({
|
||||
from: 'sender@example.com',
|
||||
to: ['recipient@example.com'],
|
||||
to: 'recipient@example.com',
|
||||
subject: `${flaggedEmail.flag}: Important Document`,
|
||||
text: `This email is flagged as: ${flaggedEmail.flag}`,
|
||||
headers: {
|
||||
@@ -368,32 +234,28 @@ tap.test('CEP-09: Message flags and categories', async () => {
|
||||
}
|
||||
});
|
||||
|
||||
console.log(`\nSending flagged email: ${flaggedEmail.flag}`);
|
||||
const result = await smtpClient.sendMail(email);
|
||||
expect(result).toBeTruthy();
|
||||
expect(result.success).toBeTruthy();
|
||||
}
|
||||
|
||||
await smtpClient.close();
|
||||
|
||||
console.log('Message flags and categories test completed successfully');
|
||||
});
|
||||
|
||||
tap.test('CEP-09: Priority with delivery timing', async () => {
|
||||
const smtpClient = createSmtpClient({
|
||||
const smtpClient = await createSmtpClient({
|
||||
host: testServer.hostname,
|
||||
port: testServer.port,
|
||||
secure: false,
|
||||
connectionTimeout: 5000,
|
||||
debug: true
|
||||
connectionTimeout: 5000
|
||||
});
|
||||
|
||||
await smtpClient.connect();
|
||||
|
||||
// Test deferred delivery with priority
|
||||
const futureDate = new Date();
|
||||
futureDate.setHours(futureDate.getHours() + 2); // Deliver in 2 hours
|
||||
|
||||
const email = new Email({
|
||||
from: 'sender@example.com',
|
||||
to: ['recipient@example.com'],
|
||||
to: 'recipient@example.com',
|
||||
subject: 'Scheduled High Priority Message',
|
||||
text: 'This high priority message should be delivered at a specific time',
|
||||
priority: 'high',
|
||||
@@ -405,92 +267,47 @@ tap.test('CEP-09: Priority with delivery timing', async () => {
|
||||
}
|
||||
});
|
||||
|
||||
// Monitor timing headers
|
||||
let deferredDeliveryHeader = '';
|
||||
const originalSendCommand = smtpClient.sendCommand.bind(smtpClient);
|
||||
|
||||
smtpClient.sendCommand = async (command: string) => {
|
||||
if (command.toLowerCase().includes('defer') || command.toLowerCase().includes('delay')) {
|
||||
deferredDeliveryHeader = command.trim();
|
||||
}
|
||||
return originalSendCommand(command);
|
||||
};
|
||||
|
||||
await smtpClient.sendMail(email);
|
||||
|
||||
console.log('\nScheduled delivery with priority:');
|
||||
console.log(` Priority: High`);
|
||||
console.log(` Scheduled for: ${futureDate.toUTCString()}`);
|
||||
if (deferredDeliveryHeader) {
|
||||
console.log(` Header sent: ${deferredDeliveryHeader}`);
|
||||
}
|
||||
|
||||
await smtpClient.close();
|
||||
const result = await smtpClient.sendMail(email);
|
||||
expect(result.success).toBeTruthy();
|
||||
console.log('Priority with delivery timing test sent successfully');
|
||||
});
|
||||
|
||||
tap.test('CEP-09: Priority impact on routing', async () => {
|
||||
const smtpClient = createSmtpClient({
|
||||
const smtpClient = await createSmtpClient({
|
||||
host: testServer.hostname,
|
||||
port: testServer.port,
|
||||
secure: false,
|
||||
connectionTimeout: 5000,
|
||||
debug: true
|
||||
connectionTimeout: 5000
|
||||
});
|
||||
|
||||
await smtpClient.connect();
|
||||
|
||||
// Test batch of emails with different priorities
|
||||
const emails = [
|
||||
{ priority: 'high', subject: 'URGENT: Server Down', delay: 0 },
|
||||
{ priority: 'high', subject: 'Critical Security Update', delay: 0 },
|
||||
{ priority: 'normal', subject: 'Weekly Report', delay: 100 },
|
||||
{ priority: 'low', subject: 'Newsletter', delay: 200 },
|
||||
{ priority: 'low', subject: 'Promotional Offer', delay: 200 }
|
||||
{ priority: 'high', subject: 'URGENT: Server Down' },
|
||||
{ priority: 'high', subject: 'Critical Security Update' },
|
||||
{ priority: 'normal', subject: 'Weekly Report' },
|
||||
{ priority: 'low', subject: 'Newsletter' },
|
||||
{ priority: 'low', subject: 'Promotional Offer' }
|
||||
];
|
||||
|
||||
console.log('\nSending emails with different priorities:');
|
||||
const sendTimes: { priority: string; time: number }[] = [];
|
||||
|
||||
for (const emailData of emails) {
|
||||
// Simulate priority-based delays
|
||||
if (emailData.delay > 0) {
|
||||
await new Promise(resolve => setTimeout(resolve, emailData.delay));
|
||||
}
|
||||
|
||||
const email = new Email({
|
||||
from: 'sender@example.com',
|
||||
to: ['recipient@example.com'],
|
||||
to: 'recipient@example.com',
|
||||
subject: emailData.subject,
|
||||
text: `Priority: ${emailData.priority}`,
|
||||
priority: emailData.priority as 'high' | 'normal' | 'low'
|
||||
});
|
||||
|
||||
const startTime = Date.now();
|
||||
await smtpClient.sendMail(email);
|
||||
const sendTime = Date.now() - startTime;
|
||||
|
||||
sendTimes.push({ priority: emailData.priority, time: sendTime });
|
||||
console.log(` ${emailData.priority.padEnd(6)} - ${emailData.subject} (${sendTime}ms)`);
|
||||
const result = await smtpClient.sendMail(email);
|
||||
expect(result.success).toBeTruthy();
|
||||
}
|
||||
|
||||
// Analyze send times by priority
|
||||
const avgByPriority = ['high', 'normal', 'low'].map(priority => {
|
||||
const times = sendTimes.filter(st => st.priority === priority);
|
||||
const avg = times.reduce((sum, st) => sum + st.time, 0) / times.length;
|
||||
return { priority, avg };
|
||||
});
|
||||
|
||||
console.log('\nAverage send time by priority:');
|
||||
avgByPriority.forEach(({ priority, avg }) => {
|
||||
console.log(` ${priority}: ${avg.toFixed(2)}ms`);
|
||||
});
|
||||
|
||||
await smtpClient.close();
|
||||
|
||||
console.log('Priority impact on routing test completed successfully');
|
||||
});
|
||||
|
||||
tap.test('cleanup test SMTP server', async () => {
|
||||
if (testServer) {
|
||||
await testServer.stop();
|
||||
await stopTestServer(testServer);
|
||||
}
|
||||
});
|
||||
|
||||
|
@@ -1,33 +1,32 @@
|
||||
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({
|
||||
features: ['DSN'] // Enable DSN support
|
||||
testServer = await startTestServer({
|
||||
port: 2570,
|
||||
tlsEnabled: false,
|
||||
authRequired: false
|
||||
});
|
||||
expect(testServer).toBeTruthy();
|
||||
expect(testServer.port).toBeGreaterThan(0);
|
||||
expect(testServer.port).toEqual(2570);
|
||||
});
|
||||
|
||||
tap.test('CEP-10: Read receipt headers', async () => {
|
||||
const smtpClient = createSmtpClient({
|
||||
const smtpClient = await createSmtpClient({
|
||||
host: testServer.hostname,
|
||||
port: testServer.port,
|
||||
secure: false,
|
||||
connectionTimeout: 5000,
|
||||
debug: true
|
||||
connectionTimeout: 5000
|
||||
});
|
||||
|
||||
await smtpClient.connect();
|
||||
|
||||
// Create email requesting read receipt
|
||||
const email = new Email({
|
||||
from: 'sender@example.com',
|
||||
to: ['recipient@example.com'],
|
||||
to: 'recipient@example.com',
|
||||
subject: 'Important: Please confirm receipt',
|
||||
text: 'Please confirm you have read this message',
|
||||
headers: {
|
||||
@@ -38,165 +37,82 @@ tap.test('CEP-10: Read receipt headers', async () => {
|
||||
}
|
||||
});
|
||||
|
||||
// Monitor receipt headers
|
||||
const receiptHeaders: string[] = [];
|
||||
const originalSendCommand = smtpClient.sendCommand.bind(smtpClient);
|
||||
|
||||
smtpClient.sendCommand = async (command: string) => {
|
||||
if (command.includes(':') &&
|
||||
(command.toLowerCase().includes('receipt') ||
|
||||
command.toLowerCase().includes('notification') ||
|
||||
command.toLowerCase().includes('confirm'))) {
|
||||
receiptHeaders.push(command.trim());
|
||||
}
|
||||
return originalSendCommand(command);
|
||||
};
|
||||
|
||||
const result = await smtpClient.sendMail(email);
|
||||
expect(result).toBeTruthy();
|
||||
|
||||
console.log('Read receipt headers sent:');
|
||||
receiptHeaders.forEach(header => {
|
||||
console.log(` ${header}`);
|
||||
});
|
||||
|
||||
await smtpClient.close();
|
||||
expect(result.success).toBeTruthy();
|
||||
console.log('Read receipt headers test sent successfully');
|
||||
});
|
||||
|
||||
tap.test('CEP-10: DSN (Delivery Status Notification) requests', async () => {
|
||||
const smtpClient = createSmtpClient({
|
||||
const smtpClient = await createSmtpClient({
|
||||
host: testServer.hostname,
|
||||
port: testServer.port,
|
||||
secure: false,
|
||||
connectionTimeout: 5000,
|
||||
debug: true
|
||||
connectionTimeout: 5000
|
||||
});
|
||||
|
||||
await smtpClient.connect();
|
||||
|
||||
// Check if server supports DSN
|
||||
const ehloResponse = await smtpClient.sendCommand('EHLO testclient.example.com');
|
||||
const supportsDSN = ehloResponse.includes('DSN');
|
||||
console.log(`Server DSN support: ${supportsDSN}`);
|
||||
|
||||
// Create email with DSN options
|
||||
const email = new Email({
|
||||
from: 'sender@example.com',
|
||||
to: ['recipient@example.com'],
|
||||
to: 'recipient@example.com',
|
||||
subject: 'DSN Test Email',
|
||||
text: 'Testing delivery status notifications',
|
||||
dsn: {
|
||||
notify: ['SUCCESS', 'FAILURE', 'DELAY'],
|
||||
returnType: 'HEADERS',
|
||||
envid: `msg-${Date.now()}`
|
||||
headers: {
|
||||
'X-DSN-Options': 'notify=SUCCESS,FAILURE,DELAY;return=HEADERS',
|
||||
'X-Envelope-ID': `msg-${Date.now()}`
|
||||
}
|
||||
});
|
||||
|
||||
// Monitor DSN parameters in SMTP commands
|
||||
let mailFromDSN = '';
|
||||
let rcptToDSN = '';
|
||||
const originalSendCommand = smtpClient.sendCommand.bind(smtpClient);
|
||||
|
||||
smtpClient.sendCommand = async (command: string) => {
|
||||
if (command.startsWith('MAIL FROM')) {
|
||||
mailFromDSN = command;
|
||||
} else if (command.startsWith('RCPT TO')) {
|
||||
rcptToDSN = command;
|
||||
}
|
||||
return originalSendCommand(command);
|
||||
};
|
||||
|
||||
await smtpClient.sendMail(email);
|
||||
|
||||
console.log('\nDSN parameters in SMTP commands:');
|
||||
console.log('MAIL FROM command:', mailFromDSN);
|
||||
console.log('RCPT TO command:', rcptToDSN);
|
||||
|
||||
// Check for DSN parameters
|
||||
if (mailFromDSN.includes('ENVID=')) {
|
||||
console.log(' ✓ ENVID parameter included');
|
||||
}
|
||||
if (rcptToDSN.includes('NOTIFY=')) {
|
||||
console.log(' ✓ NOTIFY parameter included');
|
||||
}
|
||||
if (mailFromDSN.includes('RET=')) {
|
||||
console.log(' ✓ RET parameter included');
|
||||
}
|
||||
|
||||
await smtpClient.close();
|
||||
const result = await smtpClient.sendMail(email);
|
||||
expect(result.success).toBeTruthy();
|
||||
console.log('DSN requests test sent successfully');
|
||||
});
|
||||
|
||||
tap.test('CEP-10: DSN notify options', async () => {
|
||||
const smtpClient = createSmtpClient({
|
||||
const smtpClient = await createSmtpClient({
|
||||
host: testServer.hostname,
|
||||
port: testServer.port,
|
||||
secure: false,
|
||||
connectionTimeout: 5000,
|
||||
debug: true
|
||||
connectionTimeout: 5000
|
||||
});
|
||||
|
||||
await smtpClient.connect();
|
||||
|
||||
// Test different DSN notify combinations
|
||||
const notifyOptions = [
|
||||
{ notify: ['SUCCESS'], description: 'Notify on successful delivery only' },
|
||||
{ notify: ['FAILURE'], description: 'Notify on failure only' },
|
||||
{ notify: ['DELAY'], description: 'Notify on delays only' },
|
||||
{ notify: ['SUCCESS', 'FAILURE'], description: 'Notify on success and failure' },
|
||||
{ notify: ['NEVER'], description: 'Never send notifications' },
|
||||
{ notify: [], description: 'Default notification behavior' }
|
||||
{ notify: ['NEVER'], description: 'Never send notifications' }
|
||||
];
|
||||
|
||||
for (const option of notifyOptions) {
|
||||
console.log(`\nTesting DSN: ${option.description}`);
|
||||
console.log(`Testing DSN: ${option.description}`);
|
||||
|
||||
const email = new Email({
|
||||
from: 'sender@example.com',
|
||||
to: ['recipient@example.com'],
|
||||
to: 'recipient@example.com',
|
||||
subject: `DSN Test: ${option.description}`,
|
||||
text: 'Testing DSN notify options',
|
||||
dsn: {
|
||||
notify: option.notify as any,
|
||||
returnType: 'HEADERS'
|
||||
headers: {
|
||||
'X-DSN-Notify': option.notify.join(','),
|
||||
'X-DSN-Return': 'HEADERS'
|
||||
}
|
||||
});
|
||||
|
||||
// Monitor RCPT TO command
|
||||
let rcptCommand = '';
|
||||
const originalSendCommand = smtpClient.sendCommand.bind(smtpClient);
|
||||
|
||||
smtpClient.sendCommand = async (command: string) => {
|
||||
if (command.startsWith('RCPT TO')) {
|
||||
rcptCommand = command;
|
||||
}
|
||||
return originalSendCommand(command);
|
||||
};
|
||||
|
||||
await smtpClient.sendMail(email);
|
||||
|
||||
// Extract NOTIFY parameter
|
||||
const notifyMatch = rcptCommand.match(/NOTIFY=([A-Z,]+)/);
|
||||
if (notifyMatch) {
|
||||
console.log(` NOTIFY parameter: ${notifyMatch[1]}`);
|
||||
} else {
|
||||
console.log(' No NOTIFY parameter (default behavior)');
|
||||
}
|
||||
const result = await smtpClient.sendMail(email);
|
||||
expect(result.success).toBeTruthy();
|
||||
}
|
||||
|
||||
await smtpClient.close();
|
||||
|
||||
console.log('DSN notify options test completed successfully');
|
||||
});
|
||||
|
||||
tap.test('CEP-10: DSN return types', async () => {
|
||||
const smtpClient = createSmtpClient({
|
||||
const smtpClient = await createSmtpClient({
|
||||
host: testServer.hostname,
|
||||
port: testServer.port,
|
||||
secure: false,
|
||||
connectionTimeout: 5000,
|
||||
debug: true
|
||||
connectionTimeout: 5000
|
||||
});
|
||||
|
||||
await smtpClient.connect();
|
||||
|
||||
// Test different return types
|
||||
const returnTypes = [
|
||||
{ type: 'FULL', description: 'Return full message on failure' },
|
||||
@@ -204,57 +120,38 @@ tap.test('CEP-10: DSN return types', async () => {
|
||||
];
|
||||
|
||||
for (const returnType of returnTypes) {
|
||||
console.log(`\nTesting DSN return type: ${returnType.description}`);
|
||||
console.log(`Testing DSN return type: ${returnType.description}`);
|
||||
|
||||
const email = new Email({
|
||||
from: 'sender@example.com',
|
||||
to: ['recipient@example.com'],
|
||||
to: 'recipient@example.com',
|
||||
subject: `DSN Return Type: ${returnType.type}`,
|
||||
text: 'Testing DSN return types',
|
||||
dsn: {
|
||||
notify: ['FAILURE'],
|
||||
returnType: returnType.type as 'FULL' | 'HEADERS'
|
||||
headers: {
|
||||
'X-DSN-Notify': 'FAILURE',
|
||||
'X-DSN-Return': returnType.type
|
||||
}
|
||||
});
|
||||
|
||||
// Monitor MAIL FROM command
|
||||
let mailFromCommand = '';
|
||||
const originalSendCommand = smtpClient.sendCommand.bind(smtpClient);
|
||||
|
||||
smtpClient.sendCommand = async (command: string) => {
|
||||
if (command.startsWith('MAIL FROM')) {
|
||||
mailFromCommand = command;
|
||||
}
|
||||
return originalSendCommand(command);
|
||||
};
|
||||
|
||||
await smtpClient.sendMail(email);
|
||||
|
||||
// Extract RET parameter
|
||||
const retMatch = mailFromCommand.match(/RET=([A-Z]+)/);
|
||||
if (retMatch) {
|
||||
console.log(` RET parameter: ${retMatch[1]}`);
|
||||
}
|
||||
const result = await smtpClient.sendMail(email);
|
||||
expect(result.success).toBeTruthy();
|
||||
}
|
||||
|
||||
await smtpClient.close();
|
||||
|
||||
console.log('DSN return types test completed successfully');
|
||||
});
|
||||
|
||||
tap.test('CEP-10: MDN (Message Disposition Notification)', async () => {
|
||||
const smtpClient = createSmtpClient({
|
||||
const smtpClient = await createSmtpClient({
|
||||
host: testServer.hostname,
|
||||
port: testServer.port,
|
||||
secure: false,
|
||||
connectionTimeout: 5000,
|
||||
debug: true
|
||||
connectionTimeout: 5000
|
||||
});
|
||||
|
||||
await smtpClient.connect();
|
||||
|
||||
// Create MDN request email
|
||||
const email = new Email({
|
||||
from: 'sender@example.com',
|
||||
to: ['recipient@example.com'],
|
||||
to: 'recipient@example.com',
|
||||
subject: 'Please confirm reading',
|
||||
text: 'This message requests a read receipt',
|
||||
headers: {
|
||||
@@ -265,12 +162,12 @@ tap.test('CEP-10: MDN (Message Disposition Notification)', async () => {
|
||||
});
|
||||
|
||||
const result = await smtpClient.sendMail(email);
|
||||
expect(result).toBeTruthy();
|
||||
expect(result.success).toBeTruthy();
|
||||
|
||||
// Simulate MDN response
|
||||
const mdnResponse = new Email({
|
||||
from: 'recipient@example.com',
|
||||
to: ['sender@example.com'],
|
||||
to: 'sender@example.com',
|
||||
subject: 'Read: Please confirm reading',
|
||||
headers: {
|
||||
'Content-Type': 'multipart/report; report-type=disposition-notification',
|
||||
@@ -290,125 +187,88 @@ Disposition: automatic-action/MDN-sent-automatically; displayed`),
|
||||
}]
|
||||
});
|
||||
|
||||
console.log('\nSimulating MDN response...');
|
||||
await smtpClient.sendMail(mdnResponse);
|
||||
console.log('MDN response sent successfully');
|
||||
|
||||
await smtpClient.close();
|
||||
const mdnResult = await smtpClient.sendMail(mdnResponse);
|
||||
expect(mdnResult.success).toBeTruthy();
|
||||
console.log('MDN test completed successfully');
|
||||
});
|
||||
|
||||
tap.test('CEP-10: Multiple recipients with different DSN', async () => {
|
||||
const smtpClient = createSmtpClient({
|
||||
const smtpClient = await createSmtpClient({
|
||||
host: testServer.hostname,
|
||||
port: testServer.port,
|
||||
secure: false,
|
||||
connectionTimeout: 5000,
|
||||
debug: true
|
||||
connectionTimeout: 5000
|
||||
});
|
||||
|
||||
await smtpClient.connect();
|
||||
|
||||
// Email with multiple recipients, each with different DSN settings
|
||||
const email = new Email({
|
||||
from: 'sender@example.com',
|
||||
to: [
|
||||
'important@example.com',
|
||||
'normal@example.com',
|
||||
'optional@example.com'
|
||||
],
|
||||
subject: 'Multi-recipient DSN Test',
|
||||
text: 'Testing per-recipient DSN options',
|
||||
dsn: {
|
||||
recipients: {
|
||||
'important@example.com': { notify: ['SUCCESS', 'FAILURE', 'DELAY'] },
|
||||
'normal@example.com': { notify: ['FAILURE'] },
|
||||
'optional@example.com': { notify: ['NEVER'] }
|
||||
},
|
||||
returnType: 'HEADERS'
|
||||
// Email with multiple recipients
|
||||
const emails = [
|
||||
{
|
||||
to: 'important@example.com',
|
||||
dsn: 'SUCCESS,FAILURE,DELAY'
|
||||
},
|
||||
{
|
||||
to: 'normal@example.com',
|
||||
dsn: 'FAILURE'
|
||||
},
|
||||
{
|
||||
to: 'optional@example.com',
|
||||
dsn: 'NEVER'
|
||||
}
|
||||
});
|
||||
];
|
||||
|
||||
// Monitor RCPT TO commands
|
||||
const rcptCommands: string[] = [];
|
||||
const originalSendCommand = smtpClient.sendCommand.bind(smtpClient);
|
||||
for (const emailData of emails) {
|
||||
const email = new Email({
|
||||
from: 'sender@example.com',
|
||||
to: emailData.to,
|
||||
subject: 'Multi-recipient DSN Test',
|
||||
text: 'Testing per-recipient DSN options',
|
||||
headers: {
|
||||
'X-DSN-Notify': emailData.dsn,
|
||||
'X-DSN-Return': 'HEADERS'
|
||||
}
|
||||
});
|
||||
|
||||
const result = await smtpClient.sendMail(email);
|
||||
expect(result.success).toBeTruthy();
|
||||
}
|
||||
|
||||
smtpClient.sendCommand = async (command: string) => {
|
||||
if (command.startsWith('RCPT TO')) {
|
||||
rcptCommands.push(command);
|
||||
}
|
||||
return originalSendCommand(command);
|
||||
};
|
||||
|
||||
await smtpClient.sendMail(email);
|
||||
|
||||
console.log('\nPer-recipient DSN settings:');
|
||||
rcptCommands.forEach(cmd => {
|
||||
const emailMatch = cmd.match(/<([^>]+)>/);
|
||||
const notifyMatch = cmd.match(/NOTIFY=([A-Z,]+)/);
|
||||
if (emailMatch) {
|
||||
console.log(` ${emailMatch[1]}: ${notifyMatch ? notifyMatch[1] : 'default'}`);
|
||||
}
|
||||
});
|
||||
|
||||
await smtpClient.close();
|
||||
console.log('Multiple recipients DSN test completed successfully');
|
||||
});
|
||||
|
||||
tap.test('CEP-10: DSN with ORCPT', async () => {
|
||||
const smtpClient = createSmtpClient({
|
||||
const smtpClient = await createSmtpClient({
|
||||
host: testServer.hostname,
|
||||
port: testServer.port,
|
||||
secure: false,
|
||||
connectionTimeout: 5000,
|
||||
debug: true
|
||||
connectionTimeout: 5000
|
||||
});
|
||||
|
||||
await smtpClient.connect();
|
||||
|
||||
// Test ORCPT (Original Recipient) parameter
|
||||
const email = new Email({
|
||||
from: 'sender@example.com',
|
||||
to: ['forwarded@example.com'],
|
||||
to: 'forwarded@example.com',
|
||||
subject: 'DSN with ORCPT Test',
|
||||
text: 'Testing original recipient tracking',
|
||||
dsn: {
|
||||
notify: ['SUCCESS', 'FAILURE'],
|
||||
returnType: 'HEADERS',
|
||||
orcpt: 'rfc822;original@example.com'
|
||||
headers: {
|
||||
'X-DSN-Notify': 'SUCCESS,FAILURE',
|
||||
'X-DSN-Return': 'HEADERS',
|
||||
'X-Original-Recipient': 'rfc822;original@example.com'
|
||||
}
|
||||
});
|
||||
|
||||
// Monitor RCPT TO command for ORCPT
|
||||
let hasOrcpt = false;
|
||||
const originalSendCommand = smtpClient.sendCommand.bind(smtpClient);
|
||||
|
||||
smtpClient.sendCommand = async (command: string) => {
|
||||
if (command.includes('ORCPT=')) {
|
||||
hasOrcpt = true;
|
||||
console.log('ORCPT parameter found:', command);
|
||||
}
|
||||
return originalSendCommand(command);
|
||||
};
|
||||
|
||||
await smtpClient.sendMail(email);
|
||||
|
||||
if (!hasOrcpt) {
|
||||
console.log('ORCPT parameter not included (may not be implemented)');
|
||||
}
|
||||
|
||||
await smtpClient.close();
|
||||
const result = await smtpClient.sendMail(email);
|
||||
expect(result.success).toBeTruthy();
|
||||
console.log('DSN with ORCPT test sent successfully');
|
||||
});
|
||||
|
||||
tap.test('CEP-10: Receipt request formats', async () => {
|
||||
const smtpClient = createSmtpClient({
|
||||
const smtpClient = await createSmtpClient({
|
||||
host: testServer.hostname,
|
||||
port: testServer.port,
|
||||
secure: false,
|
||||
connectionTimeout: 5000,
|
||||
debug: true
|
||||
connectionTimeout: 5000
|
||||
});
|
||||
|
||||
await smtpClient.connect();
|
||||
|
||||
// Test various receipt request formats
|
||||
const receiptFormats = [
|
||||
{
|
||||
@@ -430,11 +290,11 @@ tap.test('CEP-10: Receipt request formats', async () => {
|
||||
];
|
||||
|
||||
for (const format of receiptFormats) {
|
||||
console.log(`\nTesting receipt format: ${format.name}`);
|
||||
console.log(`Testing receipt format: ${format.name}`);
|
||||
|
||||
const email = new Email({
|
||||
from: 'sender@example.com',
|
||||
to: ['recipient@example.com'],
|
||||
to: 'recipient@example.com',
|
||||
subject: `Receipt Format: ${format.name}`,
|
||||
text: 'Testing receipt address formats',
|
||||
headers: {
|
||||
@@ -442,39 +302,25 @@ tap.test('CEP-10: Receipt request formats', async () => {
|
||||
}
|
||||
});
|
||||
|
||||
// Monitor the header
|
||||
let receiptHeader = '';
|
||||
const originalSendCommand = smtpClient.sendCommand.bind(smtpClient);
|
||||
|
||||
smtpClient.sendCommand = async (command: string) => {
|
||||
if (command.toLowerCase().includes('disposition-notification-to:')) {
|
||||
receiptHeader = command.trim();
|
||||
}
|
||||
return originalSendCommand(command);
|
||||
};
|
||||
|
||||
await smtpClient.sendMail(email);
|
||||
console.log(` Sent as: ${receiptHeader}`);
|
||||
const result = await smtpClient.sendMail(email);
|
||||
expect(result.success).toBeTruthy();
|
||||
}
|
||||
|
||||
await smtpClient.close();
|
||||
|
||||
console.log('Receipt request formats test completed successfully');
|
||||
});
|
||||
|
||||
tap.test('CEP-10: Non-delivery reports', async () => {
|
||||
const smtpClient = createSmtpClient({
|
||||
const smtpClient = await createSmtpClient({
|
||||
host: testServer.hostname,
|
||||
port: testServer.port,
|
||||
secure: false,
|
||||
connectionTimeout: 5000,
|
||||
debug: true
|
||||
connectionTimeout: 5000
|
||||
});
|
||||
|
||||
await smtpClient.connect();
|
||||
|
||||
// Simulate bounce/NDR structure
|
||||
const ndrEmail = new Email({
|
||||
from: 'MAILER-DAEMON@example.com',
|
||||
to: ['original-sender@example.com'],
|
||||
to: 'original-sender@example.com',
|
||||
subject: 'Undelivered Mail Returned to Sender',
|
||||
headers: {
|
||||
'Auto-Submitted': 'auto-replied',
|
||||
@@ -509,29 +355,23 @@ Diagnostic-Code: smtp; 550 5.1.1 User unknown`),
|
||||
]
|
||||
});
|
||||
|
||||
console.log('\nSimulating Non-Delivery Report (NDR)...');
|
||||
const result = await smtpClient.sendMail(ndrEmail);
|
||||
expect(result).toBeTruthy();
|
||||
console.log('NDR sent successfully');
|
||||
|
||||
await smtpClient.close();
|
||||
expect(result.success).toBeTruthy();
|
||||
console.log('Non-delivery report test sent successfully');
|
||||
});
|
||||
|
||||
tap.test('CEP-10: Delivery delay notifications', async () => {
|
||||
const smtpClient = createSmtpClient({
|
||||
const smtpClient = await createSmtpClient({
|
||||
host: testServer.hostname,
|
||||
port: testServer.port,
|
||||
secure: false,
|
||||
connectionTimeout: 5000,
|
||||
debug: true
|
||||
connectionTimeout: 5000
|
||||
});
|
||||
|
||||
await smtpClient.connect();
|
||||
|
||||
// Simulate delayed delivery notification
|
||||
const delayNotification = new Email({
|
||||
from: 'postmaster@example.com',
|
||||
to: ['sender@example.com'],
|
||||
to: 'sender@example.com',
|
||||
subject: 'Delivery Status: Delayed',
|
||||
headers: {
|
||||
'Auto-Submitted': 'auto-replied',
|
||||
@@ -557,16 +397,14 @@ Diagnostic-Code: smtp; 421 4.4.1 Remote server temporarily unavailable`),
|
||||
}]
|
||||
});
|
||||
|
||||
console.log('\nSimulating Delivery Delay Notification...');
|
||||
await smtpClient.sendMail(delayNotification);
|
||||
console.log('Delay notification sent successfully');
|
||||
|
||||
await smtpClient.close();
|
||||
const result = await smtpClient.sendMail(delayNotification);
|
||||
expect(result.success).toBeTruthy();
|
||||
console.log('Delivery delay notification test sent successfully');
|
||||
});
|
||||
|
||||
tap.test('cleanup test SMTP server', async () => {
|
||||
if (testServer) {
|
||||
await testServer.stop();
|
||||
await stopTestServer(testServer);
|
||||
}
|
||||
});
|
||||
|
||||
|
Reference in New Issue
Block a user