htmlmjmlemailuiux

Simplifier la création de template d'email avec MJML

MJML, ou l'outil qui vous permettra de coder facilement des mails responsive et compatible partout (Outlook, Gmail, Apple...)

Avez-vous déjà essayer d’intégrer des mails en HTML ? “C’est simple” direz-vous, “c’est comme intégrer une page classique en html”.

Figurez-vous que… non !

Vous l’avez peut-être déjà remarqué, les templates de mails sont souvent fait de cette manière :

<table>
    <tr></tr>
</table>

Ce site internet sympa vous montrent que de nombreuses propriétés css / html (comme flex, comme les div) ne sont pas supportées par plusieurs plateformes/client de mails.

Eh oui ! tout comme Internet Explorer 6 à son époque, Outlook nécessite qu’on rajoute pas mal de hack pour rendre votre code compatible. Une des techniques les plus utilisés est le VML.

De la même manière, un autre site utile montre les bonnes pratiques a utiliser pour avoir des mails qui fonctionnent partout.

Et pour finaliser le tout, c’est quand même plus dur de tester un mail qu’une page. Vous devez vraiment simuler l’envoi du mail afin de valider que le design que vous avez codé fonctionne bien chez tout le monde. Vous ne pouvez pas faire confiance à un navigateur pour faire un rendu de votre code.

Trouvez-nous une solution, s’il vous plaît !

C’est à ce moment que mjml entre en jeu.

D’après la documentation :

MJML is responsive by design on most-popular email clients, even Outlook. Write less code, save time and code more efficiently with MJML’s semantic syntax.

Ce qui signifie pour les moins anglophones d’entre-nous :

MJML est responsive par design sur la plupart des clients emails les plus populaires, même Outlook. Écrivez moins de code, et codez plus efficacement avec la syntaxe sémantique de MJML.

Je vous ai gardé le meilleur argument pour la fin : mjml est developpé par Mailjet.

Comment ça marche

Alors rien de plus simple. MJML a sa propre syntaxe sémantique, ou plus clairement ses propres balises. Ces balises sont transformés en code html avec une simple ligne de commande.

Voyez par vous même:

<mjml>
  <mj-body>
    <mj-section>
      <mj-column>

        <mj-image width="100px" src="/assets/img/logo-small.png"></mj-image>

        <mj-divider border-color="#F45E43"></mj-divider>
        <mj-text font-size="20px" color="#F45E43">Hello World</mj-text>
        
        <mj-button background-color="red" align="center" color="#ffffff" font-size="17px" font-weight="bold" href="https://google.com" width="300px">
            RSVP Today
        </mj-button>
      </mj-column>
    </mj-section>
  </mj-body>
</mjml>

Sera transformé en :

<!doctype html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office">

<head>
  <title>
  </title>
  <!--[if !mso]><!-- -->
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <!--<![endif]-->
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <style type="text/css">
    #outlook a {
      padding: 0;
    }

    body {
      margin: 0;
      padding: 0;
      -webkit-text-size-adjust: 100%;
      -ms-text-size-adjust: 100%;
    }

    table,
    td {
      border-collapse: collapse;
      mso-table-lspace: 0pt;
      mso-table-rspace: 0pt;
    }

    img {
      border: 0;
      height: auto;
      line-height: 100%;
      outline: none;
      text-decoration: none;
      -ms-interpolation-mode: bicubic;
    }

    p {
      display: block;
      margin: 13px 0;
    }
  </style>
  <!--[if mso]>
        <xml>
        <o:OfficeDocumentSettings>
          <o:AllowPNG/>
          <o:PixelsPerInch>96</o:PixelsPerInch>
        </o:OfficeDocumentSettings>
        </xml>
        <![endif]-->
  <!--[if lte mso 11]>
        <style type="text/css">
          .mj-outlook-group-fix { width:100% !important; }
        </style>
        <![endif]-->
  <!--[if !mso]><!-->
  <link href="https://fonts.googleapis.com/css?family=Ubuntu:300,400,500,700" rel="stylesheet" type="text/css">
  <style type="text/css">
    @import url(https://fonts.googleapis.com/css?family=Ubuntu:300,400,500,700);
  </style>
  <!--<![endif]-->
  <style type="text/css">
    @media only screen and (min-width:480px) {
      .mj-column-per-100 {
        width: 100% !important;
        max-width: 100%;
      }
    }
  </style>
  <style type="text/css">
    @media only screen and (max-width:480px) {
      table.mj-full-width-mobile {
        width: 100% !important;
      }

      td.mj-full-width-mobile {
        width: auto !important;
      }
    }
  </style>
</head>

<body>
  <div style="">
    <!--[if mso | IE]>
      <table
         align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600"
      >
        <tr>
          <td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
      <![endif]-->
    <div style="margin:0px auto;max-width:600px;">
      <table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;">
        <tbody>
          <tr>
            <td style="direction:ltr;font-size:0px;padding:20px 0;text-align:center;">
              <!--[if mso | IE]>
                  <table role="presentation" border="0" cellpadding="0" cellspacing="0">
                
        <tr>
      
            <td
               class="" style="vertical-align:top;width:600px;"
            >
          <![endif]-->
              <div class="mj-column-per-100 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
                <table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
                  <tr>
                    <td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;">
                      <table border="0" cellpadding="0" cellspacing="0" role="presentation" style="border-collapse:collapse;border-spacing:0px;">
                        <tbody>
                          <tr>
                            <td style="width:100px;">
                              <img height="auto" src="/assets/img/logo-small.png" style="border:0;display:block;outline:none;text-decoration:none;height:auto;width:100%;font-size:13px;" width="100" />
                            </td>
                          </tr>
                        </tbody>
                      </table>
                    </td>
                  </tr>
                  <tr>
                    <td style="font-size:0px;padding:10px 25px;word-break:break-word;">
                      <p style="border-top:solid 4px #F45E43;font-size:1px;margin:0px auto;width:100%;">
                      </p>
                      <!--[if mso | IE]>
        <table
           align="center" border="0" cellpadding="0" cellspacing="0" style="border-top:solid 4px #F45E43;font-size:1px;margin:0px auto;width:550px;" role="presentation" width="550px"
        >
          <tr>
            <td style="height:0;line-height:0;">
              &nbsp;
            </td>
          </tr>
        </table>
      <![endif]-->
                    </td>
                  </tr>
                  <tr>
                    <td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
                      <div style="font-family:Ubuntu, Helvetica, Arial, sans-serif;font-size:20px;line-height:1;text-align:left;color:#F45E43;">Hello World</div>
                    </td>
                  </tr>
                  <tr>
                    <td align="center" vertical-align="middle" style="font-size:0px;padding:10px 25px;word-break:break-word;">
                      <table border="0" cellpadding="0" cellspacing="0" role="presentation" style="border-collapse:separate;width:300px;line-height:100%;">
                        <tr>
                          <td align="center" bgcolor="red" role="presentation" style="border:none;border-radius:3px;cursor:auto;mso-padding-alt:10px 25px;background:red;" valign="middle">
                            <a href="https://google.com" style="display:inline-block;width:250px;background:red;color:#ffffff;font-family:Ubuntu, Helvetica, Arial, sans-serif;font-size:17px;font-weight:bold;line-height:120%;margin:0;text-decoration:none;text-transform:none;padding:10px 25px;mso-padding-alt:0px;border-radius:3px;" target="_blank"> RSVP Today </a>
                          </td>
                        </tr>
                      </table>
                    </td>
                  </tr>
                </table>
              </div>
              <!--[if mso | IE]>
            </td>
          
        </tr>
      
                  </table>
                <![endif]-->
            </td>
          </tr>
        </tbody>
      </table>
    </div>
    <!--[if mso | IE]>
          </td>
        </tr>
      </table>
      <![endif]-->
  </div>
</body>
</html>

Cela fait beaucoup de code et surtout beaucoup de hack pour un simple écran avec un logo, un texte et un bouton.

Mais c’est bien ce dont on a besoin pour avoir un email compatible avec tous les clients.

Développement

Vous voulez juste un code HTML compatible tout client ?

Si vous souhaitez juste récupérer un code html produit par MJML, vous pouvez très bien passer par là..

Ce qui est cool, c’est que plusieurs templates sont même disponible pour vous aider dans votre tâche.

Vous voulez intégrer l’outil dans votre flux de développement ?

Par contre si vous souhaitez intégrer juste mjml dans votre processus de développement, il vous suffira alors, dans votre projet de lancer :

yarn add mjml -D

Et de créer un script dans votre package.json par exemple.

scripts: {
    "mjml2html": "./node_modules/.bin/mjml -r template.mjml -o template.html"
}

Qui transformera alors votre fichier .mjml en .html.

Si vous utilisez Visual Studio Code, vous pouvez également installer une extension mjml pour voir en live le rendu de votre fichier.

Documentation

Vous trouverez toute les balises disponibles dans la doc.

Le mot de la fin

A l’heure de l’écriture de ce billet, on veut plus avoir à faire avec le problème des années 2000 comme Internet Explorer 6. Personnellement, je ne veux plus apprendre à faire des hack, ou apprendre un language compliqué comme le VML pour juste intégrer un email.

C’est pourquoi je préfère toujours vérifier si un outil (open-source de préférence) existe afin de m’éviter ces problèmes. Et si ça existe pas, à nous de peut-être le développer :)