Blog / Créer des emails avec React et Tailwind en utilisant Inertia Mailable

Image used for article Créer des emails avec React et Tailwind en utilisant Inertia Mailable

Créer des emails avec React et Tailwind en utilisant Inertia Mailable




TL;DR: Comment construire facilement des modèles d'emails dynamiques tout en conservant ses outils React et Tailwindcss grâce au package Inertia Mailable.




Vous trouverez un projet Laravel d’exemple sur ce Github Repository. Découvrez-en plus sur CapsulesX ou Bluesky.




Inertia Mailable est un package qui vous permet de concevoir de fabuleux emails dans un projet Laravel en tirant parti de la puissance d’InertiaJS. Créer des designs d’emails interactifs et réactifs en construisant des composants React, en les enrichissant avec TailwindCSS et en les intégrant dans vos mailables.




Ce package est en développement continu. Il a été créé dans le but de simplifier la mise en page des emails tout en conservant le même procédé que pour le reste de la plateforme web. Un template d'email pourrait ainsi correspondre à un template de page.




Cet article propose un exemple d'utilisation du package Inertia Mailable. Il suit le contexte d'un utilisateur qui s'inscrit sur la plateforme, et, à qui un email de bienvenue doit être envoyé. En partant d'un projet Laravel RILT, un Mailable sera configuré avec son template d'email Markdown par défaut. Il sera alors transféré vers un composant React en y ajoutant des classes TailwindCSS. Les étapes sont les suivantes :




Dans un premier temps, il est nécessaire de créer le fichier Mailable. Simplement en utilisant la commande Artisan : php artisan make:mail . En y ajoutant l’option markdown pour générer le visuel simultanément.



php artisan make:mail WelcomeNewUser --markdown=mail.welcome




Le Mailable correspondrait alors à ceci :



app\Mail\WelcomeNewUser.php


<?php

namespace App\Mail;

use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
use Illuminate\Queue\SerializesModels;


class WelcomeNewUser extends Mailable
{
    use Queueable, SerializesModels;

    public function __construct()
    {
    }

    public function envelope() : Envelope
    {
        return new Envelope( subject : 'Welcome New User' );
    }

    public function content() : Content
    {
        return new Content( markdown : 'mail.welcome' );
    }

    public function attachments() : array
    {
        return [];
    }
}




La partie envelope concerne le sujet, le destinataire et l'expéditeur de l'email. La partie content correspond au corps du message, qui est directement dirigé vers un fichier Blade au format Markdown situé dans le dossier resources/views/mail.



resources/views/mail/welcome.blade.php


<x-mail::message>
# Introduction

The body of your message.

<x-mail::button :url="''">
Button Text
</x-mail::button>

Thanks,<br>
{{ config('app.name') }}
</x-mail::message>




Ce fichier Blade contient deux composants Blade x-mail::message et x-mail::button . Ces composants font partie intégrante du framework Laravel. Voici un exemple de ce à quoi ressemble le composant blade x-mail::button :



vendor/laravel/framework/src/Illuminate/Mail/resources/views/html/button/blade.php


@props([
    'url',
    'color' => 'primary',
    'align' => 'center',
])
<table class="action" align="{{ $align }}" width="100%" cellpadding="0" cellspacing="0" role="presentation">
<tr>
<td align="{{ $align }}">
<table width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation">
<tr>
<td align="{{ $align }}">
<table border="0" cellpadding="0" cellspacing="0" role="presentation">
<tr>
<td>
<a href="{{ $url }}" class="button button-{{ $color }}" target="_blank" rel="noopener">{{ $slot }}</a>
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>




Pour visualiser rapidement le template d’e-mail, il est nécessaire de créer une route.



routes/web.php


<?php

use Illuminate\Support\Facades\Route;
use App\Mail\WelcomeNewUser;

Route::get( '/', fn() => ( new WelcomeNewUser() )->render() );







La personnalisation de ce template étant limitée, il est nécessaire de publier les composants pour accéder à plus d'options. Une série de fichiers apparaîtra alors dans le dossier resources/views/vendor/mail.



php artisan vendor:publish --tag=laravel-mail




Les composants Blade apparaîtront dans le dossier html, tandis que le fichier default.css se trouvera dans le dossier themes.




C’est maintenant au tour du package Inertia Mailable.



composer require capsulescodes/inertia-mailable 




L’étape suivante consiste à publier les fichiers javascript ou typescript qui géreront les composants React via InertiaJS.



// Javascript

php artisan vendor:publish --tag=inertia-mailable-react-js

// Typescript

php artisan vendor:publish --tag=inertia-mailable-react-ts


   INFO  Publishing [inertia-mailable-react-js] assets.

  Copying file [/vendor/inertia-mailable/stubs/js/react/mail.jsx] to [resources/js/mail.jsx] ............................ DONE
  Copying file [/vendor/inertia-mailable/stubs/js/react/mails/Welcome.jsx] to [resources/js/mails/Welcome.jsx] .......... DONE




Deux fichiers sont publiés, mail.jsx : le fichier d'initialisation Inertia et Welcome.jsx : le composant du mail.




Il faut ensuite ajouter le fichier Inertia nouvellement créé dans le fichier vite.config.js sous la catégorie ssr. Comme ces composants React sont générés côté serveur, ils peuvent être compilés et stockés dans un dossier inaccessible aux visiteurs.



vite.config.js


import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import tailwind from '@tailwindcss/vite';
import react from '@vitejs/plugin-react';


export default defineConfig( {
    plugins : [
        laravel( {
            input : [ 'resources/css/app.css', 'resources/js/app.jsx' ],
            ssr : [ 'resources/js/mail.jsx' ],
            refresh : true,
        }),
        tailwind(),
        react(),
    ],
    resolve : { alias : { '~': '/resources/js' } }
});




Dans le cadre de cet article un nouveau script ssr est ajouté au fichier package.json. Ce script permet de transpiler les fichiers nécessaires et de les stocker dans le dossier bootstrap/ssr. Ce script aura une utilité particulière plus tard dans cet article.



package.json


{
    "type": "module",
    "scripts": {
        "dev": "vite",
        "build": "vite build",
        "ssr": "vite build --ssr"
    },
    "dependencies" : {
        "@inertiajs/react" : "^2.0.4",
        "@tailwindcss/vite" : "^4.0.9",
        "@vitejs/plugin-react" : "^4.3.4",
        "concurrently" : "^9.0.1",
        "laravel-vite-plugin" : "^1.2.0",
        "react" : "^19.0.0",
        "react-dom" : "^19.0.0",
        "tailwindcss" : "^4.0.9",
        "vite" : "^6.0.11"
    }
}




Et de modifier le Mailable précédemment créé : WelcomeNewUser .



app\Mail\WelcomeNewUser.php


<?php

namespace App\Mail;

use Illuminate\Bus\Queueable;
- use Illuminate\Mail\Mailable;
+ use CapsulesCodes\InertiaMailable\Mail\Mailable;
- use Illuminate\Mail\Mailables\Content;
+ use CapsulesCodes\InertiaMailable\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
use Illuminate\Queue\SerializesModels;


class WelcomeNewUser extends Mailable
{
    use Queueable, SerializesModels;

    public function __construct()
    {
    }

    public function envelope() : Envelope
    {
        return new Envelope( subject : 'Welcome New User' );
    }

    public function content() : Content
    {
-       return new Content( markdown : 'mail.welcome' );
+       return new Content( view : 'Welcome', props : [ 'name' => 'Capsules Codes' ] );
    }

    public function attachments() : array
    {
        return [];
    }
}
  • Pour injecter les données dans le composant React, on utilise désormais le mot clé props contrairement à with, qui est utilisé pour l’injection de données dans les layouts Blade.




Il est temps de visualiser le rendu. Lancer préalablement npm run ssr .




Si une erreur de ce type Error: proc_open(): posix_spawn() failed: No such file or directory apparait, cela indique que Node est introuvable , il faudra alors spécifier son chemin dans une variable .env : NODE_PATH.



> ssr
> vite build --ssr

vite v5.4.2 building SSR bundle for production...
✓ 10 modules transformed.
bootstrap/ssr/ssr-manifest.json   0.81 kB
bootstrap/ssr/mail.js            13.65 kB
✓ built in 112ms







🎉




Il ne reste plus qu’à personnaliser son e-mail depuis le composant React.



resources/js/mails/Welcome.jsx


import { Layout, Subcopy } from '/vendor/capsulescodes/inertia-mailable/components/js/react/Layout';
import Table from '/vendor/capsulescodes/inertia-mailable/components/js/react/tags/Table';


function Welcome( { name } )
{
    const app = process.env.VITE_APP_NAME;
    const image = '<https://raw.githubusercontent.com/capsulescodes/inertia-mailable/main/art/capsules-inertia-mailable-mail-image.png>';


    return (

        <Layout>

            <div>

                <p className="text-slate-800">Hello, { name }!</p>

                <p className="pt-4 text-sm text-slate-600">This is a mail made with Laravel, Inertia and React</p>

                <Table align="center">

                    <Table align="center">

                        <Table>

                            <img className="my-4 max-w-full" src={ image } />

                        </Table>

                    </Table>

                </Table>

                <p className="pb-4 text-sm text-slate-600">Regards,</p>

                <p className="text-slate-800">{ app }</p>

            </div>

            <Subcopy>

                <p className="text-xs text-slate-600">This is a subcopy made with Laravel, Inertia and React</p>

            </Subcopy>

        </Layout>
    );
};


export default Welcome;
  • Pour plus de clarté, l’ajout d’un alias dans le fichier vite.config.js permet d’éviter d’importer les composants à partir de leur chemin absolu. /vendor/capsulescodes/inertia-mailable/components/react deviendrait alors @/react.




Et, cerise sur le gateau, il est possible d’éviter de transpiler les fichiers à chaque modification en utilisant l’option --watch. Cependant, il faudra rafraîchir le navigateur pour visualiser les changements.



"ssr": "vite build --ssr --watch"




Pour envoyer l’email, on ajoute une route send tout en configurant les variables .env qui concerne le Mailer.



routes/web.php


use Illuminate\Support\Facades\Route;
use Illuminate\Support\Facades\Mail;
use App\Mail\WelcomeNewUser;


Route::get( '/send', function(){ Mail::to( 'example@example.com' )->send( new WelcomeNewUser() ); } );




.env


MAIL_MAILER=log
MAIL_HOST=127.0.0.1
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS="hello@example.com"
MAIL_FROM_NAME="${APP_NAME}"








Ravi d’avoir pu aider !

v1.5.3

Icône XIcône BlueskyIcône Github