#!/usr/bin/env nu # Email optimization and compatibility processor # Transforms HTML for email client compatibility # Main email processing function export def process_email [html_content: string, config: record, dev: bool, verbose: bool] { let email_config = if "email" in ($config | columns) { $config.email } else { { enabled: false } } if not $email_config.enabled { if $verbose { print "📧 Email optimization disabled, skipping..." } return { html: $html_content, text_version: "", size: 0 } } if $verbose { print "📧 Processing email optimizations..." } # Apply email-specific transformations let optimized_html = ($html_content | inline_all_css $email_config $verbose | optimize_for_email_clients $email_config $verbose | convert_relative_urls $email_config $verbose | strip_unsupported_elements $email_config $verbose | add_email_fallbacks $email_config $verbose ) # Generate plain text version if requested let text_version = if "text_output" in ($email_config.output | columns) { generate_text_version $optimized_html $verbose } else { "" } { html: $optimized_html, text_version: $text_version, size: ($optimized_html | str length) } } # Inline all CSS for email compatibility def inline_all_css [html_content: string, email_config: record, verbose: bool] { if not $email_config.inline_css { return $html_content } if $verbose { print " 🎨 Inlining all CSS for email compatibility..." } # Extract CSS from ' '::STYLE::$1::STYLE::') let style_parts = ($style_matches | split row '::STYLE::' | where { |part| not ($part | str starts-with '::') and ($part | str length) > 0 }) for part in $style_parts { if not ($part | str starts-with '::') { $css_content = ($css_content + "\n" + $part) } } # Find all tags and read their content let link_matches = ($html_content | str find-replace -ar ']*rel="stylesheet"[^>]*href="([^"]*)"[^>]*>' '::LINK::$1::LINK::') let link_parts = ($link_matches | split row '::LINK::' | where { |part| not ($part | str starts-with '::') and ($part | str length) > 0 }) for link_url in $link_parts { if not ($link_url | str starts-with '::') { # Try to read the CSS file let css_path = if ($link_url | str starts-with 'http') { # External URL - would need http get continue } else { # Local file $link_url } if ($css_path | path exists) { let css_file_content = (open $css_path) $css_content = ($css_content + "\n" + $css_file_content) } } } # Remove all ' '' | str replace -ar ']*rel="stylesheet"[^>]*>' '' ) # Apply CSS inlining (simplified version - in production would use a proper CSS parser) let inlined_html = (apply_css_inline $html_without_css $css_content $verbose) $inlined_html } # Apply CSS rules inline to elements (simplified implementation) def apply_css_inline [html_content: string, css_content: string, verbose: bool] { # This is a simplified CSS inlining - in production, you'd use a proper CSS parser # For now, just add the CSS as an inline style block for email clients that support it let style_block = if ($css_content | str length) > 0 { $"" } else { "" } # Insert the style block in the head let result = ($html_content | str replace '' $"($style_block)\n") if $verbose { print " ✅ CSS inlined (simplified implementation)" } $result } # Optimize HTML for email client compatibility def optimize_for_email_clients [html_content: string, email_config: record, verbose: bool] { if $verbose { print " 🔧 Optimizing for email client compatibility..." } mut optimized_html = $html_content # Convert divs to tables for better Outlook compatibility if $email_config.compatibility.outlook { # This is a simplified conversion - in production would be more sophisticated $optimized_html = ($optimized_html | str replace -ar '
| ' | str replace -ar '(\s*)?' ' |
| ' ''
)
}
# Ensure proper width constraints for email
let max_width = $email_config.max_width
$optimized_html = ($optimized_html
| str replace -ar 'max-width:\s*\d+px' $"max-width: ($max_width)px"
| str replace -ar 'width:\s*100%' $"width: ($max_width)px; max-width: 100%"
)
if $verbose { print " ✅ Applied email client optimizations" }
$optimized_html
}
# Convert relative URLs to absolute URLs
def convert_relative_urls [html_content: string, email_config: record, verbose: bool] {
if not $email_config.absolute_urls {
return $html_content
}
if $verbose { print " 🔗 Converting relative URLs to absolute..." }
# This would need a base URL from config
let base_url = if "base_url" in ($email_config | columns) {
$email_config.base_url
} else {
"https://example.com"
}
let result = ($html_content
| str replace -ar 'href="(?!http|mailto|#)([^"]*)"' $'href="($base_url)/$1"'
| str replace -ar 'src="(?!http|data:)([^"]*)"' $'src="($base_url)/$1"'
)
if $verbose { print " ✅ Converted relative URLs" }
$result
}
# Remove unsupported HTML elements and CSS properties
def strip_unsupported_elements [html_content: string, email_config: record, verbose: bool] {
if not $email_config.remove_unsupported {
return $html_content
}
if $verbose { print " 🚫 Removing unsupported elements..." }
mut stripped_html = $html_content
# Remove JavaScript
if $email_config.strip_js {
$stripped_html = ($stripped_html
| str replace -ar '' ''
| str replace -ar 'on\w+="[^"]*"' ''
| str replace -ar "on\w+='[^']*'" ''
)
}
# Remove unsupported CSS properties
$stripped_html = ($stripped_html
| str replace -ar 'position:\s*(fixed|absolute|sticky);?' ''
| str replace -ar 'z-index:\s*\d+;?' ''
| str replace -ar 'transform:[^;]+;?' ''
| str replace -ar 'transition:[^;]+;?' ''
| str replace -ar 'animation:[^;]+;?' ''
| str replace -ar '@keyframes[^}]+}' ''
| str replace -ar '@media[^{]+{[^}]+}' ''
)
# Remove form elements (not well supported in email)
$stripped_html = ($stripped_html
| str replace -ar '' ''
| str replace -ar ']*>' ''
| str replace -ar '' ''
| str replace -ar '' ''
| str replace -ar '' ''
)
if $verbose { print " ✅ Removed unsupported elements" }
$stripped_html
}
# Add fallbacks for email clients
def add_email_fallbacks [html_content: string, email_config: record, verbose: bool] {
if $verbose { print " 🔄 Adding email client fallbacks..." }
mut fallback_html = $html_content
# Add fallback fonts
let fallback_fonts = ($email_config.fallback_fonts | str join ", ")
$fallback_html = ($fallback_html
| str replace -ar 'font-family:\s*[^;]+' $"font-family: ($fallback_fonts)"
)
# Add alt text to images that don't have it
$fallback_html = ($fallback_html
| str replace -ar ' |