Hello again. This tutorial will guide you through creating visually appealing emails for Laravel applications using Tailwind. This work is based on the insightful post by Ralph J. Smit (https://ralphjsmit.com/laravel-emails-tailwind-css), which has been immensely helpful. In this post, I aim to provide a comprehensive guide on how to use Tailwind with Laravel emails. I'll address two challenges that I encountered: using Vite instead of Webpack, and working with non-SMTP transports, such as Resend.
The process includes the following steps:
- Create the necessary Tailwind and Vite configurations
- Build our email views and classes
- Use an updated CSS inliner that is compatible with all transports
Tailwind Configurations
First, create a separate Tailwind configuration file. For instance, you can name it mailwind.css
. Place this file in the root of your Laravel repository.
const defaultTheme = require("tailwindcss/defaultTheme");
module.exports = {
content: ["./resources/views/emails/**/*.blade.php"],
theme: {
screens: {
xxs: "375px",
xs: "475px",
...defaultTheme.screens,
},
fontFamily: {
sans: ['"DM Sans"', "system-ui"],
filament: ["DM Sans", ...defaultTheme.fontFamily.sans],
serif: ["Georgia", "ui-serif"],
display: ['"PP Eiko"', "system-ui"],
mono: ["JetBrains Mono", "monospace"],
}
},
};
Next, create a new CSS file for our emails. Place it at resources/css/mail.css
:
@config "../../mailwind.config.js";
@tailwind utilities;
Two important points to note: Firstly, we're using the @config
directive to direct Tailwind to our new configuration. Secondly, we're only using the utilities
to generate our utility classes. We don't need the base
and components
typically found in a Tailwind CSS file, as the inliner we'll use later can struggle to handle them.
Finally, update your vite.config.js
to inform it about our new CSS file:
import { defineConfig } from "vite";
import laravel, { refreshPaths } from "laravel-vite-plugin";
export default defineConfig({
plugins: [
laravel({
input: [
"resources/css/mail.css",
"resources/css/app.css",
"resources/js/app.js",
],
refresh: [...refreshPaths, "app/Livewire/**"],
}),
],
});
Laravel Email
With Artisan, we can create a new email and assign its content to a new view that we'll create.
php artisan make:mail MyEmail
// app/Mail/MyEmail.php
public function content(): Content
{
return new Content(
view: 'emails.my-email',
);
}
Create the view in resources/views/emails/my-email.blade.php
. You're welcome to use regular Blade features here, including layouts which are particularly useful when handling multiple emails.
@php
use Illuminate\Support\Facades\Vite;
@endphp
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style>
{!! Vite::content('resources/css/mail.css') !!}
</style>
@if($subject = $attributes->get('subject'))
<title>{{ $subject }}</title>
@endif
</head>
<body>
<div class="w-full h-full p-4 m-4 border">
MY EMAIL GOES HERE
</div>
</body>
</html>
The {!! Vite::content('resources/css/mail.css') !!}
is used for outputting our compiled CSS into the style
tag that will be inlined next.
Inliner
Due to the varied behavior of email clients compared to web browsers, we need to inline styles. For instance, w-full
should be replaced with width: 100%
for each element that uses it. Don't fret, it's simpler than it sounds with the help of laravel-mail-css-inliner
. However, as of writing, this doesn't work with every transport. For instance, it wouldn't work in production when used with Resend. But there's no need to worry, you can use my fork of the project which resolves this issue.
Begin by adding the following to your composer.json
file:
"repositories": [
{
"type": "vcs",
"url": "https://github.com/jamiedavenport/laravel-mail-css-inliner.git"
}
]
To download and install the package, run the command composer require "fedeisas/laravel-mail-css-inliner @dev"
.
Conclusion
That's all for now, but not quite everything. You still need to set up and send your emails. For those steps, I suggest referring to the Laravel documentation. Once you've done that, your emails will be beautifully formatted with Tailwind.
Follow up reading:
Until next time ✌️