2025-05-24 16:19:19 +00:00
import { tap , expect } from '@git.zone/tstest/tapbundle' ;
2025-05-26 04:09:29 +00:00
import { startTestServer , stopTestServer , type ITestServer } from '../../helpers/server.loader.js' ;
import { createSmtpClient } from '../../../ts/mail/delivery/smtpclient/index.js' ;
2025-05-24 16:19:19 +00:00
import { Email } from '../../../ts/mail/core/classes.email.js' ;
2025-05-26 04:09:29 +00:00
let testServer : ITestServer ;
2025-05-24 16:19:19 +00:00
tap . test ( 'setup test SMTP server' , async ( ) = > {
2025-05-26 04:09:29 +00:00
testServer = await startTestServer ( {
port : 2568 ,
tlsEnabled : false ,
authRequired : false
} ) ;
2025-05-24 16:19:19 +00:00
expect ( testServer ) . toBeTruthy ( ) ;
2025-05-26 04:09:29 +00:00
expect ( testServer . port ) . toEqual ( 2568 ) ;
2025-05-24 16:19:19 +00:00
} ) ;
tap . test ( 'CEP-08: Basic custom headers' , async ( ) = > {
2025-05-26 04:09:29 +00:00
const smtpClient = await createSmtpClient ( {
2025-05-24 16:19:19 +00:00
host : testServer.hostname ,
port : testServer.port ,
secure : false ,
2025-05-26 04:09:29 +00:00
connectionTimeout : 5000
2025-05-24 16:19:19 +00:00
} ) ;
// Create email with custom headers
const email = new Email ( {
from : 'sender@example.com' ,
2025-05-26 04:09:29 +00:00
to : 'recipient@example.com' ,
2025-05-24 16:19:19 +00:00
subject : 'Custom Headers Test' ,
text : 'Testing custom headers' ,
headers : {
'X-Custom-Header' : 'Custom Value' ,
'X-Campaign-ID' : 'CAMP-2024-03' ,
'X-Priority' : 'High' ,
'X-Mailer' : 'Custom SMTP Client v1.0'
}
} ) ;
const result = await smtpClient . sendMail ( email ) ;
2025-05-26 04:09:29 +00:00
expect ( result . success ) . toBeTruthy ( ) ;
console . log ( 'Basic custom headers test sent successfully' ) ;
2025-05-24 16:19:19 +00:00
} ) ;
tap . test ( 'CEP-08: Standard headers override protection' , async ( ) = > {
2025-05-26 04:09:29 +00:00
const smtpClient = await createSmtpClient ( {
2025-05-24 16:19:19 +00:00
host : testServer.hostname ,
port : testServer.port ,
secure : false ,
2025-05-26 04:09:29 +00:00
connectionTimeout : 5000
2025-05-24 16:19:19 +00:00
} ) ;
// Try to override standard headers via custom headers
const email = new Email ( {
from : 'real-sender@example.com' ,
2025-05-26 04:09:29 +00:00
to : 'real-recipient@example.com' ,
2025-05-24 16:19:19 +00:00
subject : 'Real Subject' ,
text : 'Testing header override protection' ,
headers : {
'From' : 'fake-sender@example.com' , // Should not override
'To' : 'fake-recipient@example.com' , // Should not override
'Subject' : 'Fake Subject' , // Should not override
'Date' : 'Mon, 1 Jan 2000 00:00:00 +0000' , // Might be allowed
'Message-ID' : '<fake@example.com>' , // Might be allowed
'X-Original-From' : 'tracking@example.com' // Custom header, should work
}
} ) ;
2025-05-26 04:09:29 +00:00
const result = await smtpClient . sendMail ( email ) ;
expect ( result . success ) . toBeTruthy ( ) ;
console . log ( 'Header override protection test sent successfully' ) ;
2025-05-24 16:19:19 +00:00
} ) ;
tap . test ( 'CEP-08: Tracking and analytics headers' , async ( ) = > {
2025-05-26 04:09:29 +00:00
const smtpClient = await createSmtpClient ( {
2025-05-24 16:19:19 +00:00
host : testServer.hostname ,
port : testServer.port ,
secure : false ,
2025-05-26 04:09:29 +00:00
connectionTimeout : 5000
2025-05-24 16:19:19 +00:00
} ) ;
// Common tracking headers
const email = new Email ( {
from : 'marketing@example.com' ,
2025-05-26 04:09:29 +00:00
to : 'customer@example.com' ,
2025-05-24 16:19:19 +00:00
subject : 'Special Offer Inside!' ,
text : 'Check out our special offers' ,
headers : {
'X-Campaign-ID' : 'SPRING-2024-SALE' ,
'X-Customer-ID' : 'CUST-12345' ,
'X-Segment' : 'high-value-customers' ,
'X-AB-Test' : 'variant-b' ,
'X-Send-Time' : new Date ( ) . toISOString ( ) ,
'X-Template-Version' : '2.1.0' ,
'List-Unsubscribe' : '<https://example.com/unsubscribe?id=12345>' ,
'List-Unsubscribe-Post' : 'List-Unsubscribe=One-Click' ,
'Precedence' : 'bulk'
}
} ) ;
const result = await smtpClient . sendMail ( email ) ;
2025-05-26 04:09:29 +00:00
expect ( result . success ) . toBeTruthy ( ) ;
console . log ( 'Tracking and analytics headers test sent successfully' ) ;
2025-05-24 16:19:19 +00:00
} ) ;
tap . test ( 'CEP-08: MIME extension headers' , async ( ) = > {
2025-05-26 04:09:29 +00:00
const smtpClient = await createSmtpClient ( {
2025-05-24 16:19:19 +00:00
host : testServer.hostname ,
port : testServer.port ,
secure : false ,
2025-05-26 04:09:29 +00:00
connectionTimeout : 5000
2025-05-24 16:19:19 +00:00
} ) ;
// MIME-related custom headers
const email = new Email ( {
from : 'sender@example.com' ,
2025-05-26 04:09:29 +00:00
to : 'recipient@example.com' ,
2025-05-24 16:19:19 +00:00
subject : 'MIME Extensions Test' ,
html : '<p>HTML content</p>' ,
text : 'Plain text content' ,
headers : {
'MIME-Version' : '1.0' , // Usually auto-added
'X-Accept-Language' : 'en-US, en;q=0.9, fr;q=0.8' ,
'X-Auto-Response-Suppress' : 'DR, RN, NRN, OOF' ,
'Importance' : 'high' ,
'X-Priority' : '1' ,
'X-MSMail-Priority' : 'High' ,
'Sensitivity' : 'Company-Confidential'
}
} ) ;
2025-05-26 04:09:29 +00:00
const result = await smtpClient . sendMail ( email ) ;
expect ( result . success ) . toBeTruthy ( ) ;
console . log ( 'MIME extension headers test sent successfully' ) ;
2025-05-24 16:19:19 +00:00
} ) ;
tap . test ( 'CEP-08: Email threading headers' , async ( ) = > {
2025-05-26 04:09:29 +00:00
const smtpClient = await createSmtpClient ( {
2025-05-24 16:19:19 +00:00
host : testServer.hostname ,
port : testServer.port ,
secure : false ,
2025-05-26 04:09:29 +00:00
connectionTimeout : 5000
2025-05-24 16:19:19 +00:00
} ) ;
// Simulate email thread
const messageId = ` < ${ Date . now ( ) } . ${ Math . random ( ) } @example.com> ` ;
const inReplyTo = '<original-message@example.com>' ;
const references = '<thread-start@example.com> <second-message@example.com>' ;
const email = new Email ( {
from : 'sender@example.com' ,
2025-05-26 04:09:29 +00:00
to : 'recipient@example.com' ,
2025-05-24 16:19:19 +00:00
subject : 'Re: Email Threading Test' ,
text : 'This is a reply in the thread' ,
headers : {
'Message-ID' : messageId ,
'In-Reply-To' : inReplyTo ,
'References' : references ,
'Thread-Topic' : 'Email Threading Test' ,
'Thread-Index' : Buffer . from ( 'thread-data' ) . toString ( 'base64' )
}
} ) ;
2025-05-26 04:09:29 +00:00
const result = await smtpClient . sendMail ( email ) ;
expect ( result . success ) . toBeTruthy ( ) ;
console . log ( 'Email threading headers test sent successfully' ) ;
2025-05-24 16:19:19 +00:00
} ) ;
tap . test ( 'CEP-08: Security and authentication headers' , async ( ) = > {
2025-05-26 04:09:29 +00:00
const smtpClient = await createSmtpClient ( {
2025-05-24 16:19:19 +00:00
host : testServer.hostname ,
port : testServer.port ,
secure : false ,
2025-05-26 04:09:29 +00:00
connectionTimeout : 5000
2025-05-24 16:19:19 +00:00
} ) ;
// Security-related headers
const email = new Email ( {
from : 'secure@example.com' ,
2025-05-26 04:09:29 +00:00
to : 'recipient@example.com' ,
2025-05-24 16:19:19 +00:00
subject : 'Security Headers Test' ,
text : 'Testing security headers' ,
headers : {
'X-Originating-IP' : '[192.168.1.100]' ,
'X-Auth-Result' : 'PASS' ,
'X-Spam-Score' : '0.1' ,
'X-Spam-Status' : 'No, score=0.1' ,
'X-Virus-Scanned' : 'ClamAV using ClamSMTP' ,
'Authentication-Results' : 'example.com; spf=pass smtp.mailfrom=sender@example.com' ,
'ARC-Seal' : 'i=1; cv=none; d=example.com; s=arc-20240315; t=1710500000;' ,
'ARC-Message-Signature' : 'i=1; a=rsa-sha256; c=relaxed/relaxed;' ,
'ARC-Authentication-Results' : 'i=1; example.com; spf=pass'
}
} ) ;
const result = await smtpClient . sendMail ( email ) ;
2025-05-26 04:09:29 +00:00
expect ( result . success ) . toBeTruthy ( ) ;
console . log ( 'Security and authentication headers test sent successfully' ) ;
2025-05-24 16:19:19 +00:00
} ) ;
tap . test ( 'CEP-08: Header folding for long values' , async ( ) = > {
2025-05-26 04:09:29 +00:00
const smtpClient = await createSmtpClient ( {
2025-05-24 16:19:19 +00:00
host : testServer.hostname ,
port : testServer.port ,
secure : false ,
2025-05-26 04:09:29 +00:00
connectionTimeout : 5000
2025-05-24 16:19:19 +00:00
} ) ;
// Create headers with long values that need folding
const longValue = 'This is a very long header value that exceeds the recommended 78 character limit per line and should be folded according to RFC 5322 specifications for proper email transmission' ;
const email = new Email ( {
from : 'sender@example.com' ,
2025-05-26 04:09:29 +00:00
to : 'recipient@example.com' ,
2025-05-24 16:19:19 +00:00
subject : 'Header Folding Test with a very long subject line that should be properly folded' ,
text : 'Testing header folding' ,
headers : {
'X-Long-Header' : longValue ,
'X-Multiple-Values' : 'value1@example.com, value2@example.com, value3@example.com, value4@example.com, value5@example.com, value6@example.com' ,
'References' : '<msg1@example.com> <msg2@example.com> <msg3@example.com> <msg4@example.com> <msg5@example.com> <msg6@example.com> <msg7@example.com>'
}
} ) ;
2025-05-26 04:09:29 +00:00
const result = await smtpClient . sendMail ( email ) ;
expect ( result . success ) . toBeTruthy ( ) ;
console . log ( 'Header folding test sent successfully' ) ;
2025-05-24 16:19:19 +00:00
} ) ;
tap . test ( 'CEP-08: Custom headers with special characters' , async ( ) = > {
2025-05-26 04:09:29 +00:00
const smtpClient = await createSmtpClient ( {
2025-05-24 16:19:19 +00:00
host : testServer.hostname ,
port : testServer.port ,
secure : false ,
2025-05-26 04:09:29 +00:00
connectionTimeout : 5000
2025-05-24 16:19:19 +00:00
} ) ;
// Headers with special characters
const email = new Email ( {
from : 'sender@example.com' ,
2025-05-26 04:09:29 +00:00
to : 'recipient@example.com' ,
2025-05-24 16:19:19 +00:00
subject : 'Special Characters in Headers' ,
text : 'Testing special characters' ,
headers : {
'X-Special-Chars' : 'Value with special: !@#$%^&*()' ,
'X-Quoted-String' : '"This is a quoted string"' ,
'X-Unicode' : 'Unicode: café, naïve, 你好' ,
'X-Control-Chars' : 'No\ttabs\nor\rnewlines' , // Should be sanitized
'X-Empty' : '' ,
'X-Spaces' : ' trimmed ' ,
'X-Semicolon' : 'part1; part2; part3'
}
} ) ;
2025-05-26 04:09:29 +00:00
const result = await smtpClient . sendMail ( email ) ;
expect ( result . success ) . toBeTruthy ( ) ;
console . log ( 'Special characters test sent successfully' ) ;
2025-05-24 16:19:19 +00:00
} ) ;
tap . test ( 'CEP-08: Duplicate header handling' , async ( ) = > {
2025-05-26 04:09:29 +00:00
const smtpClient = await createSmtpClient ( {
2025-05-24 16:19:19 +00:00
host : testServer.hostname ,
port : testServer.port ,
secure : false ,
2025-05-26 04:09:29 +00:00
connectionTimeout : 5000
2025-05-24 16:19:19 +00:00
} ) ;
// Some headers can appear multiple times
const email = new Email ( {
from : 'sender@example.com' ,
2025-05-26 04:09:29 +00:00
to : 'recipient@example.com' ,
2025-05-24 16:19:19 +00:00
subject : 'Duplicate Headers Test' ,
text : 'Testing duplicate headers' ,
headers : {
'Received' : 'from server1.example.com' ,
'X-Received' : 'from server2.example.com' , // Workaround for multiple
'Comments' : 'First comment' ,
'X-Comments' : 'Second comment' , // Workaround for multiple
2025-05-26 04:09:29 +00:00
'X-Tag' : 'tag1, tag2, tag3' // String instead of array
2025-05-24 16:19:19 +00:00
}
} ) ;
2025-05-26 04:09:29 +00:00
const result = await smtpClient . sendMail ( email ) ;
expect ( result . success ) . toBeTruthy ( ) ;
console . log ( 'Duplicate header handling test sent successfully' ) ;
2025-05-24 16:19:19 +00:00
} ) ;
tap . test ( 'cleanup test SMTP server' , async ( ) = > {
if ( testServer ) {
2025-05-26 04:09:29 +00:00
await stopTestServer ( testServer ) ;
2025-05-24 16:19:19 +00:00
}
} ) ;
export default tap . start ( ) ;