@bernierllc/validators-email
v0.1.2
Published
Email content validation - composite validator for email campaigns combining HTML syntax, MIME structure, link integrity, and tracking validation
Readme
@bernierllc/validators-email
Email content validation - composite domain validator for email campaigns
Overview
@bernierllc/validators-email is a comprehensive domain-level validator that orchestrates multiple primitive validators to provide complete email validation. It validates HTML syntax, MIME structure, link integrity, image assets, tracking parameters, and URL normalization for email campaigns.
Installation
npm install @bernierllc/validators-emailFeatures
- HTML Syntax Validation - Validates email HTML for well-formedness
- MIME Structure Validation - Validates multipart email structure
- Link Integrity - Validates all links in email content
- Image Asset Validation - Validates image sources, alt text, and dimensions
- Tracking Parameter Validation - Validates UTM and custom tracking parameters
- URL Normalization - Normalizes URLs for consistency
- Composite Architecture - Orchestrates multiple primitive validators
- Configurable Rules - Enable/disable specific validation rules
- Detailed Problem Reporting - Returns detailed validation problems with locations
Usage
Basic Usage
import { validateEmail } from '@bernierllc/validators-email';
import { createSharedUtils } from '@bernierllc/validators-utils';
const utils = createSharedUtils();
const email = {
html: `
<!DOCTYPE html>
<html>
<body>
<h1>Welcome!</h1>
<p>Thank you for subscribing to our newsletter.</p>
<a href="https://example.com?utm_source=email&utm_campaign=welcome">
Visit our website
</a>
<img src="https://example.com/logo.png" alt="Company Logo" width="200" />
</body>
</html>
`,
subject: 'Welcome to Our Newsletter',
text: 'Welcome! Thank you for subscribing.',
};
const result = await validateEmail(email, {}, utils);
if (result.problems.length === 0) {
console.log('✓ Email is valid!');
} else {
console.log('Email validation issues:');
result.problems.forEach(problem => {
console.log(`- ${problem.message} (${problem.ruleId})`);
});
}
console.log(`Validation completed in ${result.stats.durationMs}ms`);
console.log(`Rules applied: ${result.stats.rulesApplied.join(', ')}`);Creating a Configured Validator
import { createEmailValidator } from '@bernierllc/validators-email';
import { createSharedUtils } from '@bernierllc/validators-utils';
const utils = createSharedUtils();
// Create validator with custom options
const validator = createEmailValidator({
validateHtml: true,
validateLinks: true,
validateImages: true,
validateTracking: true,
normalizeUrls: true,
validateMime: false, // Skip MIME validation
severity: 'warning',
});
// Get validator metadata
const meta = validator.getMeta();
console.log('Validator:', meta.name);
console.log('Enabled rules:', meta.enabledRules);
// Validate email
const email = {
html: '<html><body><h1>Test Email</h1></body></html>',
subject: 'Test',
};
const result = await validator.validate(email, utils);Selective Validation
import { validateEmail } from '@bernierllc/validators-email';
import { createSharedUtils } from '@bernierllc/validators-utils';
const utils = createSharedUtils();
// Only validate HTML and links, skip images and tracking
const result = await validateEmail(
{
html: '<html><body><a href="https://example.com">Link</a></body></html>',
},
{
validateHtml: true,
validateLinks: true,
validateImages: false,
validateTracking: false,
validateMime: false,
},
utils
);MIME Structure Validation
import { validateEmail } from '@bernierllc/validators-email';
import { createSharedUtils } from '@bernierllc/validators-utils';
const utils = createSharedUtils();
const email = {
html: '<html><body><p>HTML version</p></body></html>',
mime: `Content-Type: multipart/alternative; boundary="boundary123"
--boundary123
Content-Type: text/plain
Plain text version
--boundary123
Content-Type: text/html
<html><body><p>HTML version</p></body></html>
--boundary123--`,
};
const result = await validateEmail(
email,
{ validateMime: true },
utils
);Campaign Email Validation
import { validateEmail } from '@bernierllc/validators-email';
import { createSharedUtils } from '@bernierllc/validators-utils';
const utils = createSharedUtils();
const campaignEmail = {
html: `
<!DOCTYPE html>
<html>
<head>
<title>Summer Sale 2025</title>
</head>
<body>
<h1>Summer Sale - 50% Off!</h1>
<p>Don't miss our biggest sale of the year.</p>
<a href="https://example.com/sale?utm_source=email&utm_medium=newsletter&utm_campaign=summer_sale">
Shop Now
</a>
<img
src="https://example.com/images/summer-banner.jpg"
alt="Summer Sale Banner"
width="600"
height="200"
/>
<p>
<a href="https://example.com/unsubscribe?email={{email}}&token={{token}}">
Unsubscribe
</a>
</p>
</body>
</html>
`,
subject: 'Summer Sale - 50% Off Everything!',
text: 'Summer Sale - 50% Off! Visit https://example.com/sale',
metadata: {
from: '[email protected]',
to: ['[email protected]'],
},
};
const result = await validateEmail(
campaignEmail,
{
validateHtml: true,
validateLinks: true,
validateImages: true,
validateTracking: true,
normalizeUrls: true,
},
utils
);
// Check specific validation results
const htmlProblems = result.problems.filter(p => p.ruleId?.includes('html'));
const linkProblems = result.problems.filter(p => p.ruleId?.includes('link'));
const trackingProblems = result.problems.filter(p => p.ruleId?.includes('tracking'));
console.log(`HTML issues: ${htmlProblems.length}`);
console.log(`Link issues: ${linkProblems.length}`);
console.log(`Tracking issues: ${trackingProblems.length}`);API Reference
validateEmail(email, options, utils)
Validates email content using composed primitive validators.
Parameters:
email: EmailContent- Email content to validateoptions: EmailValidationOptions- Validation options (optional)utils: SharedUtils- Shared utilities from validators-utils
Returns: Promise<ValidationResult>
createEmailValidator(options)
Creates a configured email validator instance.
Parameters:
options: EmailValidationOptions- Validation options (optional)
Returns: Object with validate() and getMeta() methods
Types
EmailContent
interface EmailContent {
html: string; // HTML body content (required)
text?: string; // Plain text alternative
subject?: string; // Email subject line
mime?: string; // Raw MIME content for multipart validation
metadata?: { // Email metadata
from?: string;
to?: string[];
cc?: string[];
bcc?: string[];
headers?: Record<string, string>;
};
}EmailValidationOptions
interface EmailValidationOptions {
validateHtml?: boolean; // Validate HTML syntax (default: true)
validateMime?: boolean; // Validate MIME structure (default: true)
validateLinks?: boolean; // Validate links (default: true)
validateImages?: boolean; // Validate images (default: true)
validateTracking?: boolean; // Validate tracking params (default: true)
normalizeUrls?: boolean; // Normalize URLs (default: true)
severity?: 'error' | 'warning' | 'info'; // Problem severity (default: 'error')
}Validation Rules
HTML Syntax (email/html-syntax)
- Malformed tags
- Unclosed tags
- Invalid nesting
- Duplicate IDs
- Malformed attributes
MIME Structure (email/mime-structure)
- Valid multipart boundaries
- Proper content-type headers
- Correct MIME part structure
Link Integrity (email/link-integrity)
- Valid URL format
- Reachable links (when network checking enabled)
- Proper protocol (http/https)
- No broken anchors
Image Assets (email/image-assets)
- Valid image source URLs
- Alt text presence
- Dimension attributes
- Proper image formats
Tracking Parameters (email/tracking-params)
- Valid UTM parameters (utm_source, utm_medium, utm_campaign, etc.)
- Custom tracking parameters (mc_, track_)
- Parameter value validation
URL Normalization (email/url-normalization)
- Consistent URL formatting
- Protocol normalization
- Domain case normalization
- Path normalization
Composed Primitives
This domain validator orchestrates the following primitive validators:
@bernierllc/validators-html-syntax- HTML syntax validation@bernierllc/validators-mime-structure- MIME structure validation@bernierllc/validators-link-integrity- Link validation@bernierllc/validators-image-asset- Image validation@bernierllc/validators-tracking-params- Tracking parameter validation@bernierllc/validators-url-normalization- URL normalization
Integration Status
- Logger integration: not-applicable - Validators use @bernierllc/validators-reporters for output and problem reporting. Validators are pure functions that return structured results rather than logging directly.
- Docs-Suite: ready - Full TypeDoc documentation with examples
- NeverHub integration: not-applicable - Validators are pure, stateless functions with no need for service discovery. The @bernierllc/neverhub-adapter is not needed for this package type. Validators return structured validation results that can be consumed by any system.
Dependencies
Runtime
@bernierllc/validators-core- Core validation framework@bernierllc/validators-runner- Validation runner@bernierllc/validators-html-syntax- HTML syntax primitive@bernierllc/validators-mime-structure- MIME structure primitive@bernierllc/validators-link-integrity- Link integrity primitive@bernierllc/validators-image-asset- Image asset primitive@bernierllc/validators-tracking-params- Tracking params primitive@bernierllc/validators-url-normalization- URL normalization primitive
Development
- TypeScript 5.0+
- Jest for testing (comprehensive test suite present - ESM compatibility in progress)
- ESLint for linting
MECE Architecture
This package follows MECE (Mutually Exclusive, Collectively Exhaustive) principles as a domain validator:
- Domain Level - Orchestrates multiple primitive validators for email validation
- Composite Pattern - Combines atomic validators for comprehensive validation
- Single Responsibility - Focused on email content validation
- Pure Functions - No side effects, deterministic validation
- Type Safety - Strict TypeScript with full type coverage
See Also
- @bernierllc/validators-core - Core validation framework
- @bernierllc/validators-runner - Validation runner
- @bernierllc/validators-web - Web content validation
- @bernierllc/validators-api - API validation
License
Copyright (c) 2025 Bernier LLC. All rights reserved.
This file is licensed to the client under a limited-use license. The client may use and modify this code only within the scope of the project it was delivered for. Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.
