fedeisas/laravel-mail-css-inliner
Installation:
composer require fedeisas/laravel-mail-css-inliner
Publish the config file (optional):
php artisan vendor:publish --provider="Fedeisas\MailCssInliner\MailCssInlinerServiceProvider" --tag="config"
First Use Case:
Automatically inline CSS for all outgoing emails by adding the Inliner trait to your Mailable class:
use Fedeisas\MailCssInliner\Traits\Inliner;
class OrderConfirmationMail extends Mailable
{
use Inliner;
// Your Mailable logic...
}
The package will now inline CSS for every email sent via this class.
Quick Manual Inlining:
For one-off emails, use the MailCssInliner facade:
use Fedeisas\MailCssInliner\Facades\MailCssInliner;
$html = '<html><head><style>body { color: red; }</style></head><body>...</body></html>';
$inlinedHtml = MailCssInliner::inline($html);
Inliner trait to your base Mailable class (e.g., App\Mail\BaseMailable):
use Fedeisas\MailCssInliner\Traits\Inliner;
class BaseMailable extends Mailable
{
use Inliner;
}
Override the shouldInlineCss() method in your Mailable:
public function shouldInlineCss(): bool
{
return $this->isProduction(); // Only inline in production
}
Configure via .env or config/mail-css-inliner.php:
MAIL_CSS_INLINER_ENABLED=true
MAIL_CSS_INLINER_EXCLUDE_CLASSES=admin-notification
MAIL_CSS_INLINER_REMOVE_STYLES=false
Use @inlineCss directive in Blade emails:
@inlineCss
<style>
.button { background: blue; }
</style>
<button class="button">Click</button>
The package works seamlessly with Laravel's queue system. CSS is inlined before the email is queued or sent.
Pass dynamic HTML to the facade and inline it on-the-fly:
$dynamicHtml = view('emails.dynamic', ['data' => $data])->render();
$inlinedHtml = MailCssInliner::inline($dynamicHtml);
Use preserveStyles to keep specific styles intact:
MailCssInliner::inline($html, [
'preserveStyles' => ['font-family', 'color'],
]);
Skip inlining for certain mailables by overriding shouldInlineCss():
public function shouldInlineCss(): bool
{
return !in_array($this->subject, ['Newsletter', 'Digest']);
}
Mock the inliner in tests:
$this->app->shouldReceive('make')
->with('Fedeisas\MailCssInliner\MailCssInliner')
->andReturn(new class {
public function inline($html) { return $html; } // No-op
});
Bind a custom inliner in AppServiceProvider:
$this->app->bind('Fedeisas\MailCssInliner\MailCssInliner', function ($app) {
return new CustomInliner($app['config']);
});
!important sparingly..env settings may not reflect changes immediately due to Laravel's caching.php artisan config:clear
<style> tags may not inline correctly.<link> tags or use the preserveStyles option.Add this to your Mailable to debug:
protected function getHtmlContent()
{
$html = parent::getHtmlContent();
\Log::debug('Inlined HTML:', ['html' => $html]);
return $html;
}
$html = tidy($html, ['indent' => true, 'wrap' => 256]);
Add classes to MAIL_CSS_INLINER_EXCLUDE_CLASSES in .env:
MAIL_CSS_INLINER_EXCLUDE_CLASSES=problem-class,another-issue
php -v
If emails appear unchanged after config updates:
php artisan view:clear
Extend the MailCssInliner class:
namespace App\Services;
use Fedeisas\MailCssInliner\MailCssInliner as BaseInliner;
class CustomInliner extends BaseInliner
{
protected function shouldInlineStyle($selector)
{
// Custom logic to filter styles
return parent::shouldInlineStyle($selector) && !str_contains($selector, 'no-inline');
}
}
Bind it in AppServiceProvider:
$this->app->bind('Fedeisas\MailCssInliner\MailCssInliner', function ($app) {
return new CustomInliner($app['config']);
});
Use Laravel's Mail event listeners to modify HTML before inlining:
Mail::send(function ($m) {
$m->to('user@example.com');
$m->subject('Test');
$m->html(view('emails.test'));
})->after(function ($message) {
if ($message->hasTo('user@example.com')) {
$message->html = MailCssInliner::inline($message->html);
}
});
Listen to Creating event to conditionally inline:
use Illuminate\Mail\Events\MessageSending;
event(new MessageSending($message));
// Access $message->html and modify before sending
Inject additional styles before inlining:
$html = '<style>body { font-family: Arial; }</style>' . $html;
$inlinedHtml = MailCssInliner::inline($html);
Use media queries in <style> tags and preserve them:
MailCssInliner::inline($html, [
'preserveStyles' => ['@media (prefers-color-scheme: dark)'],
]);
How can I help you explore Laravel packages today?