How to send e-mails in Laravel with Tailwind CSS | RJS

How to send e-mails in Laravel with Tailwind CSS

Learn how to create beautiful e-mails in Laravel with Tailwind CSS.

Ralph J. Smit Laravel & PHP-developer.

Tailwind CSS is an awesome tool to build beautiful websites and apps. And Laravel is the one of the best frameworks to rapidly build complete applications.

Building HTML- or Blade-templates for e-mails is always a hassle and unpleasant. As you might know, e-mail clients do not support separate stylesheets. This means that you have to inline all your CSS in every email template. That's awfully unpleasant, right?

If you are a seasoned developer (or not yet so seasoned), you might want to use Tailwind CSS in Laravel e-mail templates as well. Luckily, I found an easy way to pass Tailwind CSS to your Laravel template mails.

How to create Laravel email templates with Tailwind CSS

The process for using Tailwind CSS in Laravel e-mails is a simple four-step proces:

  1. Create an e-mail template and use Tailwind CSS in the template.
  2. Create a separate CSS-file (mail.css) and run Tailwind CSS with a separate config.
  3. Let the e-mail template extend a base HTML-template.
  4. Inline the Tailwind CSS using a CSS inliner.

Can you also use Maizzle framework for Tailwind CSS?

If you have looked for this before, you might have come across the Maizzle Framework. This is a framework that sells itself as a framework for "Rapid Email Prototyping". Why shouldn't you use that?

There are two reasons for that. Personally, I find the documentation of Maizzle very hard to understand. Second, Maizzle requires you to build your HTML-files outside of your regular Laravel-project. I really dislike that, because I want all my files to be in the same Git-repository, without having to switch between multiple open projects or editors.

1. Create a new e-mail template and use Tailwind CSS

1.1 Create a Blade-file

First, we'll want to create the Blade-file for our e-mail template. Go to your resources/views directory and create a new directory called mails with a file order-created.blade.php inside it (of course, you can use a custom name).

Inside this file, you can add some simple Blade-code:

<div>
<h1 class="text-4xl tracking-tight font-bold">My title!</h1>
<!-- More code -->
</div>

1.2 Create a Laravel Mail class

Next, create a new Mail class with the following artisan command:

php artisan make:mail OrderCreated

This will create the following file in your project. Update the name of the view in the build() function to be the name of the file you created above:

<?php
 
namespace App\Mail;
 
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
 
class OrderCreated extends Mailable
{
use Queueable, SerializesModels;
 
/**
* Create a new message instance.
*
* @return void
*/
public function __construct()
{
//
}
 
/**
* Build the message.
*
* @return $this
*/
public function build()
{
return $this->view('mails.order-created');
}
}

2. Create a special `mail.css` file with Tailwind CSS

In your resources/css directory, create a new mail.css file. You can also give the file an other name.

This CSS-file will contain the Tailwind-classes for all your e-mails. You do not need a special CSS-file for each e-mail template, since all the styles are going to be inlined anyway.

Add the following contents to the mail.css file:

@tailwind base;
@tailwind components;
@tailwind utilities;

Next, we need to create a separate Tailwind CSS configuration file for our e-mails. Create a tailwind-mail.config.js file in the root of your project.

Please update the content key to only scan the resources/views/mails/**/*.blade.php files. The rest of the file you can configure like you wish, but here's an example from me:

const defaultTheme = require('tailwindcss/defaultTheme');
const colors = require('tailwindcss/colors')
 
module.exports = {
content: [
'./resources/views/mails/**/*.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']
},
extend: {
colors: {
danger: colors.rose,
primary: colors.sky,
success: colors.lime,
warning: colors.yellow,
},
},
},
plugins: [
require('@tailwindcss/forms'),
require('@tailwindcss/typography'),
],
}

Next, you should update your webpack.mix.js file and update the file to the following:

const mix = require('laravel-mix');
/* Add this line to the top if you do not have this: */
const tailwindcss = require('tailwindcss');
 
mix.js('resources/js/app.js', 'public/js')
.postCss('resources/css/app.css', 'public/css', [
require("tailwindcss")
])
/* Add the next three lines: */
.postCss('resources/css/mail.css', 'public/css', [
tailwindcss('tailwind-mail.config.js')
])
.version();

I'll assume that already have Tailwind CSS installed in Laravel. If not, follow the official guide on the Tailwind CSS website.

3. Create a Blade-component with the base layout

The next thing we should do, is create a sort of base Blade-template that every individual Laravel e-mail template uses. The equivalent of the layouts/app.blade.php file, but now for e-mails.

I'll create this as a view component, meaning that we create a Blade and PHP file.

I created a resources/mails/base.blade.php template, but you are free to choose your own location. Add the following contents:

<!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" />
 
<!-- The CSS stylesheet which will be inlined. -->
<link rel="stylesheet" type="text/css" href="{{ mix('css/mail.css') }}">
 
@if($subject = $attributes->get('subject'))
<title>{{ $subject }}</title>
@endif
</head>
<body>
<div class="w-full h-full px-8 py-12">
{{ $slot }}
</div>
</body>
</html>

Next, create a PHP-file in the app/View/Components folder (or somewhere else). Add the following contents:

<?php
 
namespace App\View\Components;
 
use Illuminate\Contracts\View\View;
use Illuminate\View\Component;
 
class Base extends Component
{
public function render(): View
{
// Update the name of your view.
return view('mails.base');
}
}

Finally, we should register the component in a service provider:

Blade::component('mails.base', \App\Views\Components\Base::class);

Now we can use the Blade-component like <x-mails.blade>. Finally, update the initial view file you created to fit inside the Blade-component:

<x-mails.base :subject="$subject">
<!-- Your e-mail content -->
</x-mails.base>

Great! You're almost ready now. As a short recap, what we did was create a Blade layout component for the default HTML-markup in our mails, create a mail.css file to contain our Tailwind CSS classes and create a Blade-file with our regular Laravel e-mail template.

4. Inline Laravel e-mail CSS with the CSS inliner

The final step we need to do before this works, is inlining the CSS. To do so, we'll require a Laravel-package via Composer that automatically takes care of inlining the CSS into the e-mails.

If you're using Laravel 9, you should make sure that you install version 5 (if that is released) or the dev-master branch as a temporary fix. The problem is that – at the moment of writing (May 2022) – the author didn't yet officially release a version with support for Laravel 9.

composer require fedeisas/laravel-mail-css-inliner
 
# If it complains about version constraints:
composer require "fedeisas/laravel-mail-css-inliner:dev-master"

Now, all the CSS in your e-mails will automatically be inlined from the stylesheet in the <head> of the page.

Conclusion

As you've seen, using Tailwind CSS for your Laravel e-mails is not difficult. It just requires a little bit of setup and to know the right tricks.

Published by Ralph J. Smit on in Laravel. Last updated on 09 June 2022.


Like what you read?

Get notified when I publish something new, and unsubscribe at any time.