laravel-mail-builder maintained by dophp
Laravel Mail Builder (dophp/laravel-mail-builder)
A modular, Outlook-bulletproof email building, auditing, and compilation engine for Laravel applications.
Requires PHP 8.3+ and Laravel 12 or 13. Maintained by doPHP.
Key Features
- 29 Modular Responsive Slots: Pre-built responsive components that collapse smoothly to 100% width on mobile devices, with Microsoft Outlook MSO conditional table compatibility.
- Universal Compilation Engine: Compile modular slots or structured
EmailDocumentinstances into inlined responsive HTML (EmailSlotCompiler) or interactive AMP for Email (AmpEmailCompiler). - Liquid-Style Personalization: Fast token interpolation supporting uppercase, lowercase, capitalize, date formatting, currency, number, pluralize, default values, and inline conditionals (
{% if condition %}...{% else %}...{% endif %}). - Deliverability & Spam Auditor: Automatic pre-flight auditing calculating spam trigger scores, missing unsubscribe headers, image-to-text ratios, dark mode color inversion contrast, and live DNS deliverability checks (SPF, DMARC, BIMI).
- Multi-Device Screenshot Simulation: Adapter interface for testing email rendering across Outlook Windows (120 DPI), Apple Mail iOS 17 Dark Mode, macOS Sonoma, and Gmail Android.
- Theme & Typography Engine: Built-in design system presets (Corporate Slate, Midnight Indigo, Emerald SaaS, Warm Sunset, Monochrome Minimal) with automatic Google Fonts web font imports and Outlook fallback font stacks.
- Bidirectional Ingestion: Export templates to HTML, Plain Text, MJML, or ZIP packages—and reverse-parse external raw HTML or standard MJML into native modular slots.
- WCAG 2.1 AA Contrast Auditor: Exact mathematical relative luminance algorithm evaluating text and button contrast compliance.
- Enterprise Transport: Send via
TemplateMailablewith RFC 8058 1-click unsubscribe headers, custom attachments, and automatic CID (Content-ID) inline image embedding. - Filament Visual Builder: Full Filament builder schema component with audience targeting and conditional visibility rules.
Installation
composer require dophp/laravel-mail-builder
Publish configuration and views (optional):
php artisan vendor:publish --tag=mail-builder-config
php artisan vendor:publish --tag=mail-builder-views
Configuration
config/mail-builder.php sets the default layout theme (width, fonts, colors) and the footer identity used when a slot doesn't provide one:
MAIL_BUILDER_COMPANY_NAME="Acme Inc." # defaults to APP_NAME
MAIL_BUILDER_ADDRESS="123 Example St, Springfield"
CAN-SPAM and similar laws require a physical mailing address in marketing email, so set MAIL_BUILDER_ADDRESS or pass address to each footer slot.
Quick Start
1. Building and Compiling an Email
use DoPHP\MailBuilder\MailBuilder;
use DoPHP\MailBuilder\Enums\SlotType;
// Fluent EmailDocument API
$doc = MailBuilder::document(
subject: 'Welcome to the Platform, {{ contact.first_name }}!',
previewText: 'Get started with your new account in 3 easy steps.'
);
$doc->append(SlotType::Header, [
'brand_name' => 'Acme Corp',
'logo_url' => 'https://example.com/logo.png',
]);
$doc->append(SlotType::Hero, [
'title' => 'Accelerate Your Workflow',
'subtitle' => 'Everything you need to deliver world-class projects.',
'button_text' => 'Get Started',
'button_url' => 'https://example.com/onboarding',
]);
$doc->append(SlotType::TwoColumn, [
'left_title' => 'Cloud Infrastructure',
'left_body' => 'Deploy high-availability services across 30+ edge regions.',
'right_title' => 'RevOps Analytics',
'right_body' => 'Real-time pipeline tracking and automated revenue forecasting.',
'reverse_stack_on_mobile' => true,
]);
$doc->append(SlotType::AppBadges, [
'heading' => 'Download Our Mobile App',
'app_store_url' => 'https://apps.apple.com/app/acme',
'google_play_url' => 'https://play.google.com/store/apps/acme',
]);
$doc->append(SlotType::Footer, [
'company_name' => 'Acme Inc.',
'address' => '548 Market St, San Francisco, CA',
'unsubscribe_url' => '{{ unsubscribe_url }}',
]);
// Compile to responsive inlined HTML
$html = MailBuilder::compile($doc);
// Extract plain text fallback
$plainText = MailBuilder::plainText($doc);
2. Personalization & Merge Tags
Personalization supports dot-notation object paths, Liquid filters, and inline conditionals:
$template = "Hello {{ contact.first_name | capitalize }}! Member since {{ contact.created_at | date: 'F Y' }}. Balance: {{ account.balance | currency: 'USD' }}. {% if contact.is_vip %}Your VIP bonus is ready.{% else %}Upgrade today.{% endif %}";
$interpolated = MailBuilder::interpolate($template, [
'contact' => [
'first_name' => 'alexandra',
'created_at' => '2026-03-15 10:00:00',
'is_vip' => true,
],
'account' => [
'balance' => 1250.00,
],
]);
Built-in tags are {{unsubscribe_url}}, {{current_year}}, and {{web_view_url}}. Register your application's own tags so they appear in the Filament builder's tag picker and in previews:
use DoPHP\MailBuilder\MergeTags\MergeTagRegistry;
// In a service provider's register() method
$this->callAfterResolving(MergeTagRegistry::class, function (MergeTagRegistry $registry): void {
$registry->register('Customer', [
'{{customer.first_name}}' => 'Customer first name',
'{{customer.plan}}' => 'Subscription plan',
], [
// Sample values used when previewing templates
'customer' => ['first_name' => 'Alex', 'plan' => 'Pro'],
]);
});
Available Filters:
capitalize,title,lower,upper,trimdate: 'Format'(PHPdate()formatting)currency: 'USD'number: 2(decimal places)pluralize: 'item', 'items'truncate: 50default: 'fallback value'
3. Ingestion (HTML & MJML Import)
Import external templates into editable modular slots:
// Ingest raw HTML
$docFromHtml = MailBuilder::importHtml($rawHtml, 'Imported Newsletter');
// Ingest standard MJML
$docFromMjml = MailBuilder::importMjml($mjmlCode, 'Imported Campaign');
// Compile imported documents directly
$compiledHtml = MailBuilder::compile($docFromMjml);
4. Deliverability, Performance & Accessibility Audits
// 1. Run Pre-flight Deliverability & Spam Audit
$audit = MailBuilder::audit($html);
if (! $audit->passes) {
// Inspect $audit->critical_issues, $audit->warnings, and $audit->spam_score
}
// 2. WCAG 2.1 AA/AAA Color Contrast Audit
$contrast = MailBuilder::wcagContrast('#2563eb', '#ffffff');
// Returns: ['ratio' => 4.56, 'aa_normal' => true, 'rating' => 'AA']
$themeAudit = MailBuilder::auditContrast($themeArray);
// 3. Render Performance Benchmark
$benchmark = MailBuilder::benchmarkRender($html);
// Returns: dom_nodes_count, nested_table_depth, 3G/4G/5G download times
// 4. Sender Domain DNS Validation
$dns = MailBuilder::validateDns('yourdomain.com');
// Checks: SPF, DMARC (p=reject/quarantine), and BIMI
5. Sending Emails via TemplateMailable
use DoPHP\MailBuilder\Mail\TemplateMailable;
use Illuminate\Support\Facades\Mail;
Mail::to('user@example.com')->send(
new TemplateMailable(
template: $doc,
data: [
'contact' => ['first_name' => 'Sarah'],
'unsubscribe_url' => 'https://example.com/unsubscribe/token',
],
subjectLine: 'Exclusive Offer for {{ contact.first_name }}',
embedCidImages: true // Embeds local & base64 images as MIME CID parts
)
);
6. Filament Visual Builder Integration
Requires filament/forms ^5.0. To integrate the modular slot builder into any Filament Resource:
use DoPHP\MailBuilder\Filament\Components\EmailSlotBuilder;
public static function form(Schema $schema): Schema
{
return $schema->components([
EmailSlotBuilder::make('slots'),
]);
}
Supported Slot Types (29 Total)
| Slot Type | Key | Description |
|---|---|---|
| Header & Logo | header |
Branding bar with logo, web-view link, and optional date |
| Hero Banner | hero |
Headline, badge pill, subtext, and bulletproof CTA button |
| Text & Content | body_text |
Editorial rich text with merge tags and alignments |
| CTA Button | button |
Bulletproof Outlook VML action button |
| 2-Column Grid | two_column |
Side-by-side cards with reverse mobile stacking (rtl) |
| 3-Column Grid | three_column |
Three responsive feature cards |
| 4-Column Wall | four_column |
Partner logo trust wall or compact icon links |
| Asymmetric Split | asymmetric_columns |
1/3 + 2/3 editorial sidebar split |
| Feature List | features |
Bulleted list with icons, bold titles, and descriptions |
| Testimonial | testimonial |
Quote callout with star rating and author attribution |
| Stat Box | stat_box |
Key metric numbers and percentage badges |
| Divider Line | divider |
Horizontal rule or spacer with configurable height |
| Labeled Divider | labeled_divider |
Horizontal line with centered text badge (e.g. "OR") |
| Social Links | social_links |
Multi-channel social icon bar |
| App Badges | app_badges |
Official Apple App Store and Google Play buttons |
| Data Table | data_table |
Multi-column comparison table with zebra striping |
| Image Banner | image_banner |
Responsive banner image with alt text and link |
| Video Card | video_card |
Thumbnail with play button overlay linking to video |
| Pricing Grid | pricing_grid |
Multi-tier pricing cards with featured plan highlight |
| Rating Scale | rating_bar |
1-Click NPS or CSAT survey buttons (1-10 or 1-5 scale) |
| Countdown Urgency | countdown_timer |
Urgency banner with deadline and offer CTA |
| Accordion / FAQ | accordion |
Stacked Q&A cards for policies and instructions |
| Dynamic Feed | dynamic_feed |
Product recommendation grid with live JSON hydration |
| Order Receipt | order_receipt |
Itemized invoice summary with taxes and subtotals |
| RSS Article Feed | rss_feed |
Syndicated blog digest with publication dates |
| Product Catalog | product_catalog |
Ecommerce cards with compare-at pricing and buy CTAs |
| Coupon Code | coupon_code |
Promo voucher card with dashed border and expiry |
| Footer & Compliance | footer |
CAN-SPAM / GDPR address and unsubscribe link |
| Custom Raw HTML | html |
Bespoke HTML code component |
Testing
composer install
composer test # Pest, via Orchestra Testbench
composer analyse # PHPStan level 8 with Larastan
License
The MIT License (MIT). See LICENSE.md.