layout-09-email-envelope

Enveloppe de mailing — garde, colonne de 600, trois aplats pleins

Poser la coquille d'un mailing avec ce que le moteur Word d'Outlook sait réellement rendre : une table de garde pleine largeur qui porte le fond, une colonne de 600 px centrée qui porte tout le contenu, et l'espacement entièrement délégué au padding des cellules — jamais à une gouttière, une position ou un calcul. Les trois zones (bandeau, corps, pied) sont trois aplats PLEINS et différents, ce qui est à la fois la signature de la charte et le seul modèle de hiérarchie qu'un client mail rende à l'identique partout.

layoutemail600×611px18 benchmarks

Télécharger le .zip

Le fragment RÉEL, dans son propre document, sur le sol de sa charte — pas une image. Ce que vous voyez est exactement ce que vous collerez.

Employer quand

Toute lettre d'information ou mailing transactionnel à composer soi-même : c'est le squelette dans lequel on pose ensuite les blocs de contenu (list-06-email-digest, card-13-email-figure-band, tous deux calibrés sur le slot de 520 px). Le bandeau porte l'émetteur et le numéro d'édition, le pied porte les mentions et le désabonnement — deux zones qu'on ne peut pas omettre et qu'on réécrit sinon à chaque envoi.

Éviter quand

Le message est une page web déguisée (une landing dans un mail se lit mal et se coupe), il doit tenir plusieurs colonnes de contenu côte à côte au-delà de deux (elles ne s'empilent pas sur mobile sans requête de média, que la plupart des clients ignorent), ou la charte visée repose sur des rayons, des ombres ou des couleurs translucides — Outlook les rend en angles vifs, sans ombre et en couleur pleine, et le résultat n'est plus la charte.

Notes

Premier pattern du corpus écrit NATIVEMENT pour l'email, et non extrait d'une slide. Il inverse la méthode : au lieu de reproduire une composition puis de constater qu'elle ne passe pas la cible, on part des propriétés que le moteur Word rend, et on compose avec celles-là seulement. `node bin/emit.mjs layout-09-email-envelope --target email` sort le HTML à styles aplatis, sans bloquant. Un benchmark est écrit en PIXELS et non en ratio — la largeur de 600. C'est délibéré et c'est la seule exception du dépôt : 600 px n'est pas une échelle qu'on pourrait multiplier comme les 1600 d'une slide, c'est la largeur du volet de lecture d'Outlook. Un ratio n'aurait rien mesuré, puisqu'il n'y a rien à mettre à l'échelle. La charte ref-04 tient sa hiérarchie sur DEUX corps (le titre-monstre et la micro-typo), délibérément sans taille intermédiaire. Le canal impose d'en ajouter une troisième : un corps de lecture à 16 px. Un mail se lit sur un téléphone à bout de bras, et un micro-texte de 8 px — parfaitement lisible projeté sur un mur — y est illisible. Le benchmark de plancher (aucun corps sous 10 px) est là pour que cette entorse soit une décision mesurée et non une dérive. Deux gestes valent d'être recopiés partout ailleurs : les capitales sont ÉCRITES dans le markup (Outlook n'applique pas `text-transform`, un titre en bas de casse sortirait en bas de casse), et le fond du bouton est porté par la CELLULE et non par le lien (un `<a>` à qui on donne un aplat ne remplit rien dans Outlook).

Mots-clés

emailmailingnewsletterlettrecoquillegabaritoutlooktable600bandeaupieddesabonnementboutonctaenveloppe

Benchmarks — la géométrie, en assertions vérifiables

Rejouables par node bin/check.mjs layout-09-email-envelope : le pattern se prouve, il ne se croit pas.

assertionmesureattendu
LA COLONNE FAIT EXACTEMENT 600 px — la largeur de sécurité du canal, pas une échelleW600 ± 0
marge de cellule ≈ 6,7 % de la colonne (40 px)num('.vl-emenv__head','paddingLeft') / W0.0667 ± 0.006
toutes les zones partagent la MÊME marge latérale — un mail qui décale se lit comme deux mailsMath.abs(num('.vl-emenv__head','paddingLeft') - num('.vl-emenv__band','paddingLeft')) + Math.abs(num('.vl-emenv__head','paddingLeft') - num('.vl-emenv__foot','paddingLeft'))≤ 0.5
la colonne est centrée dans la gardeMath.abs((0 - box('.vl-emenv').left) - (box('.vl-emenv').right - W))≤ 1.5
TROIS aplats, et trois DIFFÉRENTS : bandeau, corps, piednew Set(['.vl-emenv__band','.vl-emenv__body','.vl-emenv__foot'].map((s) => getComputedStyle(document.querySelector(s)).backgroundColor)).size3 ± 0
aucun aplat translucide : Outlook ignore l'alpha et rendrait la couleur PLEINEMath.min(...['.vl-emenv__band','.vl-emenv__body','.vl-emenv__foot','.vl-emenv__cta','.vl-emenv__col'].map((s) => { const p = (getComputedStyle(document.querySelector(s)).backgroundColor.match(/[\d.]+/g) || []).map(Number); return p.length === 4 ? p[3] : 1; }))1 ± 0
aucun rayon nulle part — signature de la charte, et zéro dégradation dans Outlook['.vl-emenv__col','.vl-emenv__band','.vl-emenv__cta','.vl-emenv__foot'].reduce((a, s) => a + parseFloat(getComputedStyle(document.querySelector(s)).borderTopLeftRadius), 0)0 ± 0
le bouton passe le plancher tactile de 44 pxbox('.vl-emenv__cta').h≥ 44
le bouton reste un bouton : pas plus de la moitié de la colonnebox('.vl-emenv__cta').w / W≤ 0.5
saut typographique titre / corps ≥ 2,4 — la charte n'a pas de taille intermédiairenum('.vl-emenv__title','fontSize') / num('.vl-emenv__lede','fontSize')≥ 2.4
PLANCHER DE LISIBILITÉ : aucun corps de texte sous 10 px, micro-typo compriseMath.min(...[...document.querySelectorAll('.vl-emenv__col *')].filter((e) => !e.children.length && e.textContent.trim()).map((e) => parseFloat(getComputedStyle(e).fontSize)))≥ 10
contraste du nom d'émetteur sur le bandeau ≥ 4,5contrast('.vl-emenv__wordmark')≥ 4.5
contraste du numéro d'édition ≥ 4,5 — c'est le plus petit corps du bandeaucontrast('.vl-emenv__issue')≥ 4.5
contraste du libellé de bouton ≥ 4,5contrast('.vl-emenv__ctalink')≥ 4.5
contraste de la rubrique grise ≥ 4,5 — trois lots de suite, la source la plaçait juste dessouscontrast('.vl-emenv__kicker')≥ 4.5
contraste des mentions de pied ≥ 4,5contrast('.vl-emenv__legal')≥ 4.5
le désabonnement reste identifiable sans la couleur : il est soulignécs('.vl-emenv__unsub','textDecorationLine').includes('underline') ? 1 : 01 ± 0
aucun débordement de la colonneoverflow('.vl-emenv__col')≤ 0

Le code

fragment — patterns/layout-09-email-envelope.html Télécharger
<!-- layout-09-email-envelope — la coquille d'un mailing, écrite NATIVEMENT pour le canal.

     Le corpus est de la matière slide/web : au 11/08/2026 aucun des 38 patterns antérieurs ne
     passait `bin/emit.mjs --target email`. Celui-ci est écrit à l'envers — on part de ce que le
     moteur Word d'Outlook sait rendre, et on compose avec ça seulement : deux tables emboîtées
     (garde pleine largeur + colonne de 600 px centrée), l'espacement porté par le PADDING DES
     CELLULES et jamais par une gouttière, aucune position, aucun calc(), aucun SVG, aucun rayon,
     aucune ombre, aucune couleur à canal alpha.

     Les capitales sont ÉCRITES dans le markup et non obtenues par `text-transform` : Outlook
     n'applique pas la propriété, un titre en bas de casse sortirait en bas de casse.

     Couleurs via --vl-* uniquement. Les trois aplats pleins qui alternent (bandeau, corps, pied)
     sont la signature de ref-04 — et le seul modèle de hiérarchie qu'un client mail rende à
     l'identique partout. -->
<table class="vl-emenv" role="presentation" cellpadding="0" cellspacing="0" border="0" width="100%">
  <tr>
    <td class="vl-emenv__yard" align="center">

      <table class="vl-emenv__col" role="presentation" cellpadding="0" cellspacing="0" border="0" width="600" align="center">

        <!-- 1 · BANDEAU — premier aplat. Deux cellules, pas un flex : c'est la seule façon
             d'obtenir « à gauche / à droite » qui tienne dans les six clients majeurs. -->
        <tr>
          <td class="vl-emenv__band">
            <table class="vl-emenv__bandrow" role="presentation" cellpadding="0" cellspacing="0" border="0" width="100%">
              <tr>
                <td class="vl-emenv__wordmark" align="left">NORTHBEAM</td>
                <td class="vl-emenv__issue" align="right">ÉDITION 118 · 11 AOÛT</td>
              </tr>
            </table>
          </td>
        </tr>

        <!-- 2 · TITRE, CHAPÔ, CORPS — deuxième aplat -->
        <tr>
          <td class="vl-emenv__head">
            <div class="vl-emenv__kicker">LETTRE HEBDOMADAIRE</div>
            <h1 class="vl-emenv__title">CE QUE LA COURBE DES TAUX NE DIT PAS ENCORE</h1>
          </td>
        </tr>
        <tr>
          <td class="vl-emenv__body">
            <p class="vl-emenv__lede">Trois mouvements de la semaine, et ce qu'ils changent pour une
              allocation qui court sur dix ans. La lettre complète se lit en quatre minutes.</p>
            <!-- slot body : y poser list-06-email-digest ou card-13-email-figure-band,
                 tous deux calibrés sur 520 px = 600 − 2 × 40 de marge de cellule. -->
          </td>
        </tr>

        <!-- Bouton : le fond et le padding sont portés par la CELLULE, jamais par le lien.
             Un `<a>` à qui on donne un fond ne remplit rien dans Outlook. -->
        <tr>
          <td class="vl-emenv__ctacell" align="left">
            <table class="vl-emenv__ctabox" role="presentation" cellpadding="0" cellspacing="0" border="0" align="left">
              <tr>
                <td class="vl-emenv__cta" align="center">
                  <a class="vl-emenv__ctalink" href="https://northbeam.invalid/lettre">LIRE LA LETTRE</a>
                </td>
              </tr>
            </table>
          </td>
        </tr>

        <!-- 3 · PIED — troisième aplat. Le désabonnement est SOULIGNÉ : sur un aplat sombre,
             la couleur seule ne suffit pas à désigner un lien. -->
        <tr>
          <td class="vl-emenv__foot">
            <div class="vl-emenv__legal">NORTHBEAM SAS · 12 QUAI DE LA MÉGISSERIE · 75001 PARIS</div>
            <div class="vl-emenv__legal">VOUS RECEVEZ CETTE LETTRE PARCE QUE VOUS Y ÊTES ABONNÉ.</div>
            <div class="vl-emenv__unsubline"><a class="vl-emenv__unsub" href="https://northbeam.invalid/stop">SE DÉSABONNER</a></div>
          </td>
        </tr>

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

<style>
/* La garde : elle n'existe que pour donner un fond à la fenêtre de lecture et pour centrer la
   colonne. Aucun padding — c'est la colonne qui porte toutes les marges. */
.vl-emenv { width: 100%; border-collapse: collapse; }
.vl-emenv__yard {
  padding: 32px 0;
  background: var(--vl-bg);
  font-family: "Helvetica Neue", Inter, Arial, sans-serif;
}
/* 600 px : la largeur de sécurité du canal. Ce n'est pas une échelle qu'on pourrait multiplier
   comme sur une slide — c'est le volet de lecture d'Outlook. Un pixel de plus déclenche la
   barre horizontale ou la réduction automatique sur mobile. */
.vl-emenv__col {
  width: 600px;
  border-collapse: collapse;
  background: var(--vl-white);
  margin: 0 auto;
}
.vl-emenv__bandrow { width: 100%; border-collapse: collapse; }

.vl-emenv__band { background: var(--vl-blue); padding: 20px 40px; }
.vl-emenv__wordmark {
  color: var(--vl-white);
  font-size: 15px; line-height: 18px; font-weight: 800; letter-spacing: 0.14em;
}
.vl-emenv__issue {
  color: var(--vl-white);
  font-size: 11px; line-height: 18px; font-weight: 500; letter-spacing: 0.1em;
}

.vl-emenv__head { background: var(--vl-white); padding: 40px 40px 0; }
.vl-emenv__kicker {
  margin: 0 0 14px;
  color: var(--vl-ink-muted);
  font-size: 11px; line-height: 14px; font-weight: 600; letter-spacing: 0.14em;
}
/* Le titre-monstre du système, ramené au canal. Le rapport titre / corps reste au-dessus de
   2,4 : c'est lui la signature, pas la valeur en pixels. */
.vl-emenv__title {
  margin: 0;
  color: var(--vl-black);
  font-size: 40px; line-height: 40px; font-weight: 800; letter-spacing: -0.02em;
}
.vl-emenv__body { background: var(--vl-white); padding: 22px 40px 4px; }
.vl-emenv__lede {
  margin: 0;
  color: var(--vl-black);
  font-size: 16px; line-height: 25px; font-weight: 400;
}

.vl-emenv__ctacell { background: var(--vl-white); padding: 26px 40px 44px; }
.vl-emenv__ctabox { border-collapse: collapse; }
/* 46 px de haut : au-dessus du plancher tactile de 44 px. Le padding est vertical ET
   horizontal sur la cellule, parce qu'un lien inline ne peut pas grandir une cellule. */
.vl-emenv__cta { background: var(--vl-blue); padding: 16px 34px; }
.vl-emenv__ctalink {
  color: var(--vl-white);
  font-size: 13px; line-height: 14px; font-weight: 700; letter-spacing: 0.1em;
  text-decoration: none;
}

.vl-emenv__foot { background: var(--vl-black); padding: 28px 40px 30px; }
.vl-emenv__legal {
  margin: 0 0 7px;
  color: var(--vl-ink-muted-invert);
  font-size: 11px; line-height: 16px; font-weight: 500; letter-spacing: 0.04em;
}
.vl-emenv__unsubline { margin: 5px 0 0; font-size: 11px; line-height: 16px; }
.vl-emenv__unsub {
  color: var(--vl-white);
  font-size: 11px; line-height: 16px; font-weight: 600; letter-spacing: 0.08em;
  text-decoration: underline;
}
</style>
tokens de la charte — systems/ref-04-swiss-investor-blue.json Télécharger
:root {
  --vl-bg: #D9D2C7;
  --vl-board: #D9D2C7;
  --vl-blue: #1B44D8;
  --vl-black: #0D0D0D;
  --vl-white: #FFFFFF;
  --vl-ink-muted: #6E6E6E;
  --vl-ink-muted-invert: #D3D3D3;
  --vl-hairline: #00000018;
  --vl-hairline-invert: #FFFFFF33;
  --vl-ph-a: #C9C9C9;
  --vl-ph-b: #5A5A5A;
  --vl-margin: 48px;
}
les métadonnées — patterns/layout-09-email-envelope.json (télécharger)
{
  "name": "Enveloppe de mailing — garde, colonne de 600, trois aplats pleins",
  "family": "layout",
  "ref": "ref-04-swiss-investor-blue",
  "intent": "Poser la coquille d'un mailing avec ce que le moteur Word d'Outlook sait réellement rendre : une table de garde pleine largeur qui porte le fond, une colonne de 600 px centrée qui porte tout le contenu, et l'espacement entièrement délégué au padding des cellules — jamais à une gouttière, une position ou un calcul. Les trois zones (bandeau, corps, pied) sont trois aplats PLEINS et différents, ce qui est à la fois la signature de la charte et le seul modèle de hiérarchie qu'un client mail rende à l'identique partout.",
  "when_to_use": "Toute lettre d'information ou mailing transactionnel à composer soi-même : c'est le squelette dans lequel on pose ensuite les blocs de contenu (list-06-email-digest, card-13-email-figure-band, tous deux calibrés sur le slot de 520 px). Le bandeau porte l'émetteur et le numéro d'édition, le pied porte les mentions et le désabonnement — deux zones qu'on ne peut pas omettre et qu'on réécrit sinon à chaque envoi.",
  "avoid_when": "Le message est une page web déguisée (une landing dans un mail se lit mal et se coupe), il doit tenir plusieurs colonnes de contenu côte à côte au-delà de deux (elles ne s'empilent pas sur mobile sans requête de média, que la plupart des clients ignorent), ou la charte visée repose sur des rayons, des ombres ou des couleurs translucides — Outlook les rend en angles vifs, sans ombre et en couleur pleine, et le résultat n'est plus la charte.",
  "media": [
    "email"
  ],
  "tags": [
    "email",
    "mailing",
    "newsletter",
    "lettre",
    "coquille",
    "gabarit",
    "outlook",
    "table",
    "600",
    "bandeau",
    "pied",
    "desabonnement",
    "bouton",
    "cta",
    "enveloppe"
  ],
  "vars": [
    {
      "name": "--vl-bg",
      "role": "fond de la garde — la couleur de la fenêtre de lecture autour de la colonne",
      "default": "#D9D2C7"
    },
    {
      "name": "--vl-white",
      "role": "aplat de la colonne : titre, corps, bouton",
      "default": "#FFFFFF"
    },
    {
      "name": "--vl-blue",
      "role": "aplat du bandeau ET du bouton — la couleur d'action, jamais un accent posé sur du blanc",
      "default": "#1B44D8"
    },
    {
      "name": "--vl-black",
      "role": "aplat du pied, et encre du titre",
      "default": "#0D0D0D"
    },
    {
      "name": "--vl-ink-muted",
      "role": "rubrique au-dessus du titre",
      "default": "#6E6E6E"
    },
    {
      "name": "--vl-ink-muted-invert",
      "role": "mentions légales, sur l'aplat du pied",
      "default": "#D3D3D3"
    }
  ],
  "slots": [
    "wordmark",
    "issue",
    "kicker",
    "title",
    "body",
    "cta",
    "legal",
    "unsub"
  ],
  "geometry": {
    "root": ".vl-emenv__col",
    "frame": [
      600,
      611
    ],
    "ratios": {
      "cell_pad_over_width": 0.0667,
      "band_pad_y_over_width": 0.0333,
      "title_over_lede": 2.5,
      "cta_height_over_width": 0.077
    },
    "type_px": {
      "title": 40,
      "lede": 16,
      "wordmark": 15,
      "cta": 13,
      "micro": 11
    },
    "pad_ratio": {
      "top": 0.0667,
      "x": 0.0667,
      "bottom": 0.05
    }
  },
  "benchmarks": [
    {
      "name": "LA COLONNE FAIT EXACTEMENT 600 px — la largeur de sécurité du canal, pas une échelle",
      "measure": "W",
      "expect": 600,
      "tol": 0
    },
    {
      "name": "marge de cellule ≈ 6,7 % de la colonne (40 px)",
      "measure": "num('.vl-emenv__head','paddingLeft') / W",
      "expect": 0.0667,
      "tol": 0.006
    },
    {
      "name": "toutes les zones partagent la MÊME marge latérale — un mail qui décale se lit comme deux mails",
      "measure": "Math.abs(num('.vl-emenv__head','paddingLeft') - num('.vl-emenv__band','paddingLeft')) + Math.abs(num('.vl-emenv__head','paddingLeft') - num('.vl-emenv__foot','paddingLeft'))",
      "max": 0.5
    },
    {
      "name": "la colonne est centrée dans la garde",
      "measure": "Math.abs((0 - box('.vl-emenv').left) - (box('.vl-emenv').right - W))",
      "max": 1.5
    },
    {
      "name": "TROIS aplats, et trois DIFFÉRENTS : bandeau, corps, pied",
      "measure": "new Set(['.vl-emenv__band','.vl-emenv__body','.vl-emenv__foot'].map((s) => getComputedStyle(document.querySelector(s)).backgroundColor)).size",
      "expect": 3,
      "tol": 0
    },
    {
      "name": "aucun aplat translucide : Outlook ignore l'alpha et rendrait la couleur PLEINE",
      "measure": "Math.min(...['.vl-emenv__band','.vl-emenv__body','.vl-emenv__foot','.vl-emenv__cta','.vl-emenv__col'].map((s) => { const p = (getComputedStyle(document.querySelector(s)).backgroundColor.match(/[\\d.]+/g) || []).map(Number); return p.length === 4 ? p[3] : 1; }))",
      "expect": 1,
      "tol": 0
    },
    {
      "name": "aucun rayon nulle part — signature de la charte, et zéro dégradation dans Outlook",
      "measure": "['.vl-emenv__col','.vl-emenv__band','.vl-emenv__cta','.vl-emenv__foot'].reduce((a, s) => a + parseFloat(getComputedStyle(document.querySelector(s)).borderTopLeftRadius), 0)",
      "expect": 0,
      "tol": 0
    },
    {
      "name": "le bouton passe le plancher tactile de 44 px",
      "measure": "box('.vl-emenv__cta').h",
      "min": 44
    },
    {
      "name": "le bouton reste un bouton : pas plus de la moitié de la colonne",
      "measure": "box('.vl-emenv__cta').w / W",
      "max": 0.5
    },
    {
      "name": "saut typographique titre / corps ≥ 2,4 — la charte n'a pas de taille intermédiaire",
      "measure": "num('.vl-emenv__title','fontSize') / num('.vl-emenv__lede','fontSize')",
      "min": 2.4
    },
    {
      "name": "PLANCHER DE LISIBILITÉ : aucun corps de texte sous 10 px, micro-typo comprise",
      "measure": "Math.min(...[...document.querySelectorAll('.vl-emenv__col *')].filter((e) => !e.children.length && e.textContent.trim()).map((e) => parseFloat(getComputedStyle(e).fontSize)))",
      "min": 10
    },
    {
      "name": "contraste du nom d'émetteur sur le bandeau ≥ 4,5",
      "measure": "contrast('.vl-emenv__wordmark')",
      "min": 4.5
    },
    {
      "name": "contraste du numéro d'édition ≥ 4,5 — c'est le plus petit corps du bandeau",
      "measure": "contrast('.vl-emenv__issue')",
      "min": 4.5
    },
    {
      "name": "contraste du libellé de bouton ≥ 4,5",
      "measure": "contrast('.vl-emenv__ctalink')",
      "min": 4.5
    },
    {
      "name": "contraste de la rubrique grise ≥ 4,5 — trois lots de suite, la source la plaçait juste dessous",
      "measure": "contrast('.vl-emenv__kicker')",
      "min": 4.5
    },
    {
      "name": "contraste des mentions de pied ≥ 4,5",
      "measure": "contrast('.vl-emenv__legal')",
      "min": 4.5
    },
    {
      "name": "le désabonnement reste identifiable sans la couleur : il est souligné",
      "measure": "cs('.vl-emenv__unsub','textDecorationLine').includes('underline') ? 1 : 0",
      "expect": 1,
      "tol": 0
    },
    {
      "name": "aucun débordement de la colonne",
      "measure": "overflow('.vl-emenv__col')",
      "max": 0
    }
  ],
  "notes": "Premier pattern du corpus écrit NATIVEMENT pour l'email, et non extrait d'une slide. Il inverse la méthode : au lieu de reproduire une composition puis de constater qu'elle ne passe pas la cible, on part des propriétés que le moteur Word rend, et on compose avec celles-là seulement. `node bin/emit.mjs layout-09-email-envelope --target email` sort le HTML à styles aplatis, sans bloquant.\n\nUn benchmark est écrit en PIXELS et non en ratio — la largeur de 600. C'est délibéré et c'est la seule exception du dépôt : 600 px n'est pas une échelle qu'on pourrait multiplier comme les 1600 d'une slide, c'est la largeur du volet de lecture d'Outlook. Un ratio n'aurait rien mesuré, puisqu'il n'y a rien à mettre à l'échelle.\n\nLa charte ref-04 tient sa hiérarchie sur DEUX corps (le titre-monstre et la micro-typo), délibérément sans taille intermédiaire. Le canal impose d'en ajouter une troisième : un corps de lecture à 16 px. Un mail se lit sur un téléphone à bout de bras, et un micro-texte de 8 px — parfaitement lisible projeté sur un mur — y est illisible. Le benchmark de plancher (aucun corps sous 10 px) est là pour que cette entorse soit une décision mesurée et non une dérive.\n\nDeux gestes valent d'être recopiés partout ailleurs : les capitales sont ÉCRITES dans le markup (Outlook n'applique pas `text-transform`, un titre en bas de casse sortirait en bas de casse), et le fond du bouton est porté par la CELLULE et non par le lien (un `<a>` à qui on donne un aplat ne remplit rien dans Outlook).",
  "id": "layout-09-email-envelope"
}

À côté