Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Emogrifier Laravel Package

pelago/emogrifier

Emogrifier converts CSS from blocks and stylesheets into inline style attributes in HTML. Ideal for HTML email rendering in clients with poor CSS support (e.g., Outlook, Gmail), ensuring consistent styling across email and mobile readers.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture Fit

  • Email & Transactional Messaging Systems: Ideal for Laravel applications handling transactional emails (e.g., password resets, notifications) or marketing emails where CSS support is inconsistent (Outlook, Gmail, mobile clients).
  • Hybrid HTML/CSS Workflows: Fits seamlessly into Laravel’s Blade templating for dynamic email generation (e.g., Mailables or Mailable classes).
  • Modularity: Lightweight (~1MB) and dependency-free (except PHP core), making it non-intrusive to existing Laravel stacks.
  • Extensibility: Supports post-processing (e.g., HtmlPruner, CssToAttributeConverter) for optimization, aligning with Laravel’s service-layer patterns.

Integration Feasibility

  • Laravel Service Provider: Can be bootstrapped as a service provider to centralize email processing (e.g., EmailServiceProvider with a CssInliner facade).
  • Queueable Jobs: Integrates with Laravel’s queue system for async email rendering (critical for high-volume systems).
  • Blade Directives: Custom Blade directives (e.g., @emogrify) to inline CSS during template rendering.
  • API Responses: Useful for API-driven email generation (e.g., Mail::send() with dynamic HTML).

Technical Risk

  • CSS Selector Limitations: Partial support for modern CSS (e.g., no :hover, @media queries beyond all|screen|print). Risk mitigated by allowlisting critical selectors.
  • Performance Overhead: Inlining CSS on large HTML (e.g., complex templates) may introduce latency. Benchmark with real-world email templates (e.g., 50KB HTML).
  • Edge Cases: Dynamic class names (e.g., Laravel’s {{ $user->id }}) may break selector matching. Solution: Sanitize/whitelist dynamic selectors.
  • DOM Manipulation: Uses DOMDocument, which can be memory-intensive for malformed HTML. Validate input with Laravel’s Html facade or tidy.

Key Questions

  1. Use Case Priority:
    • Is this for transactional emails (low volume, strict formatting) or marketing emails (high volume, complex templates)?
    • Will dynamic content (e.g., user-specific classes) require runtime selector generation?
  2. Performance SLAs:
    • What’s the max acceptable latency for email rendering? (Test with CssInliner::fromHtml() on production-scale templates.)
  3. Fallback Strategy:
    • How will unsupported CSS (e.g., @font-face) be handled? (Option: Graceful degradation with addExcludedCssSelector().)
  4. Testing:
    • Are there pre-built email templates to validate against? (Use tools like Email on Acid for cross-client testing.)
  5. Maintenance:
    • Will the package be long-term supported? (MIT license + active maintenance is a plus.)

Integration Approach

Stack Fit

  • Laravel Ecosystem:
    • Mailables: Extend Mailable to use CssInliner in build() or render().
    • SwiftMailer: Integrate with Laravel’s Swift_Transport for SMTP delivery.
    • Horizon/Queues: Offload processing to queues for async rendering.
  • Frontend Stack:
    • Blade: Custom directives (e.g., @emogrify) to inline CSS during template compilation.
    • Tailwind/PostCSS: Pre-process CSS to avoid unsupported selectors (e.g., purge unused classes).
  • Testing:
    • Pest/Laravel: Mock CssInliner in unit tests for email services.
    • BrowserStack: Test rendered emails across clients (Outlook, Gmail, Apple Mail).

Migration Path

  1. Phase 1: Proof of Concept
    • Replace a single email template (e.g., password reset) with CssInliner.
    • Compare rendered output against manual inlining (e.g., using Premailer).
  2. Phase 2: Service Layer
    • Create a EmailRenderer service class:
      class EmailRenderer {
          public function render(Mailable $mailable): string {
              $html = $mailable->render();
              return CssInliner::fromHtml($html)
                  ->inlineCss($mailable->css())
                  ->render();
          }
      }
      
    • Register as a Laravel service provider.
  3. Phase 3: Queue Integration
    • Wrap rendering in a job (e.g., RenderEmailJob) for async processing.
    • Use Laravel’s queue workers to handle load spikes.
  4. Phase 4: Optimization
    • Add HtmlPruner to remove display: none elements and redundant classes.
    • Implement caching for static email templates (e.g., Cache::remember()).

Compatibility

  • Laravel Versions: Compatible with LTS versions (8.x–11.x). Test with PHP 8.1+ (required by package).
  • CSS Frameworks:
    • Tailwind: Use @apply sparingly (may generate unsupported selectors).
    • Bootstrap: Prefer utility classes over complex components.
  • Dynamic Content:
    • Avoid user-generated class names in selectors (sanitize or allowlist).
    • Use data attributes (e.g., data-user-id) for dynamic styling.

Sequencing

  1. Template Design:
    • Design emails with inline-first CSS (avoid @import or external stylesheets).
    • Use semantic HTML (e.g., <table> for layouts, not divs).
  2. Development:
    • Start with static templates, then add dynamic content.
    • Use Blade directives for conditional inlining (e.g., @emogrify($css)).
  3. Deployment:
    • Roll out to non-critical emails first (e.g., newsletters).
    • Monitor failure rates (e.g., malformed HTML) via Laravel logs.
  4. Monitoring:
    • Track rendering time (e.g., telescope:metrics).
    • Set up alerts for emails failing to inline CSS.

Operational Impact

Maintenance

  • Dependencies:
    • Minimal: Only PHP core and Composer autoloader. No Laravel-specific dependencies.
    • Updates: Monitor for breaking changes (e.g., CSS selector support). Test upgrades with CI pipelines.
  • Debugging:
    • Log failed inlining (e.g., unsupported selectors) to Laravel’s log channel.
    • Use ->getDomDocument()->saveHTML() to inspect intermediate HTML.
  • Documentation:
    • Add internal docs for:
      • Allowed/excluded selectors.
      • Performance tuning (e.g., disableStyleBlocksParsing()).
      • Fallback strategies for unsupported CSS.

Support

  • Common Issues:
    • Broken layouts: Often due to unsupported selectors (e.g., :nth-child). Solution: Manual overrides or addExcludedCssSelector().
    • Slow rendering: Large HTML or complex CSS. Solution: Optimize templates (e.g., flatten nesting).
    • Outlook-specific bugs: Use Outlook’s "litmus" mode for testing.
  • Support Channels:
    • GitHub Issues: For package bugs.
    • Internal Slack/Teams: For integration questions.
    • Email Testing Tools: Litmus, Email on Acid.

Scaling

  • Horizontal Scaling:
    • Queue workers: Distribute rendering across multiple servers.
    • Caching: Cache rendered HTML for static emails (e.g., marketing templates).
  • Vertical Scaling:
    • Memory limits: Increase memory_limit for large templates (e.g., 1024M).
    • OpCache: Enable PHP OpCache to speed up CssInliner execution.
  • Database Impact:
    • None: Purely in-memory processing (no DB writes).
    • Storage: Cache rendered emails in Redis or S3 for reuse.

Failure Modes

Failure Scenario Impact Mitigation
Malformed HTML input Crashes DOMDocument Validate with filter_var($html, FILTER_VALIDATE_HTML) or tidy.
Unsupported CSS selectors Partial rendering Log warnings; use addExcludedCssSelector() for unsupported rules.
High memory usage Worker timeouts Optimize templates; increase memory_limit.
Queue job failures Delayed emails Implement retries with exponential backoff.
CSS variable evaluation failures
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
directorytree/privacy-filter-classifier
directorytree/privacy-filter
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
22h/doctrine-garbage-collection-bundle
agtp/agtp-php
agtp/mod-php
splash/sonata-admin
splash/metadata
splash/openapi
splash/scopes
splash/toolkit
testo/output-teamcity
testo/bridge-symfony
spatie/flare-daemon-runtime