`<Tailwind>`: Outlook.com ignores every media query after the first, because the generated `<style>` has adjacent `}}`

Abierto Apto para principiantes
#3,889 0 comentarios 0 reacciones 0 asignados Ver en GitHub

Los mantenedores suelen responder en 1 día

Nadie ha tomado este issue todavía.

Evaluación

Dificultad
2/5
Tiempo estimado
1-3 horas
Aptitud para principiantes
78/100
Tipo de issue
Error
Claridad
Bien especificado
Estado de actividad
Activo
Stack tecnológico
react, tailwindcss, typescript
Área
frontend

Línea de trabajo

Empieza en packages/react-email/src/components/tailwind/tailwind.tsx, en generate(nonInlineStyles), y lee cómo se serializa la hoja de estilos; el issue también señala downlevel-for-email-clients.ts para consultar las adaptaciones existentes para clientes de correo. Comprueba la salida generada de <style> con varios bloques @media y confirma que haya espacios en blanco entre llaves de cierre adyacentes y que se conserven las reglas CSS.

Escrito por el modelo de indexación a partir del texto del issue.

Descripción

Type: Bug
What versions are you using? (if relevant)

[email protected] (bundled / render), [email protected] (latest of both at time of writing)

Describe the Bug

Outlook.com deletes everything in a <style> element that comes after two adjacent closing braces, }}. This is a long-standing client bug, documented in hteumeuleu/email-bugs#92. The documented workaround is any whitespace between the braces (} }).

<Tailwind> puts every non-inlinable rule in its own @media block and writes the stylesheet minified (generate(nonInlineStyles) in tailwind.tsx). Every block ends in }} and they all share one <style>, so Outlook.com keeps the first @media block and drops the rest.

In practice only one responsive (sm:, md:, …) or dark: rule per email works in Outlook.com. Columns that sit side by side through sm: widths stay stacked at desktop width, and only the first dark-mode colour applies. I've also seen the same thing in Outlook on the web with a Microsoft 365 mailbox and in the new Outlook for Windows.

The CSS is valid, so strictly this is Outlook's bug. But <Tailwind> already adapts its output for email clients (downlevel-for-email-clients.ts), and fixing it there would cover everyone who uses responsive or dark: classes. render(..., { pretty: true }) doesn't help: the <style> contents keep their }}.

Suggested fix: when writing the non-inlinable stylesheet, put whitespace between adjacent closing braces (} }). Merging identical media queries would not be enough on its own: with two different queries (a breakpoint and dark:), the second block still comes after a }}.

What is affected (leave empty if unsure)

Tailwind Component

Link to the code that reproduces this issue

https://github.com/lpolito/react-email-outlook-double-brace

Minimal, self-contained (react-email + tailwindcss only). Core of render.tsx:

import { Body, Head, Html, render, Tailwind } from "react-email";

// Four boxes, each red inline and turned green by its own `sm:` rule.
const Email = () => (
  <Tailwind>
    <Html>
      <Head />
      <Body>
        <div className="bg-[#cf222e] sm:bg-[#1a7f37]">Box 1</div>
        <div className="bg-[#cf222e] sm:bg-[#1f883d]">Box 2</div>
        <div className="bg-[#cf222e] sm:bg-[#2da44e]">Box 3</div>
        <div className="bg-[#cf222e] sm:bg-[#116329]">Box 4</div>
      </Body>
    </Html>
  </Tailwind>
);

const html = await render(<Email />);
To Reproduce
npm install
npm run render

This writes out/raw.html (react-email's output, unchanged) and out/spaced.html (the same, with one space between each pair of adjacent closing braces inside <style>). The generated <style>:

@media (min-width: 40rem) {
  .sm_bg-_1a7f37 {
    background-color: rgb(26, 127, 55) !important;
  }
}
@media (min-width: 40rem) {
  .sm_bg-_1f883d {
    background-color: rgb(31, 136, 61) !important;
  }
}
@media (min-width: 40rem) {
  .sm_bg-_2da44e {
    background-color: rgb(45, 164, 78) !important;
  }
}
@media (min-width: 40rem) {
  .sm_bg-_116329 {
    background-color: rgb(17, 99, 41) !important;
  }
}

Open both in Outlook.com at desktop width (I used Litmus's Outlook.com client in Chrome).

out/raw.html: box 1 is green, boxes 2–4 stay red.

Outlook.com, raw output: only box 1 is green

out/spaced.html: all four are green. (A Microsoft promo pop-up covers part of the top.)

Outlook.com, spaced output: all four boxes are green

Expected Behavior

Every @media block that <Tailwind> generates survives in Outlook.com, so all four boxes are green at desktop width.

What's your node version? (if relevant)

v24.18.0

Lenguaje dominante
TypeScript
Estrellas
19.9k
Forks
1.1k
Merge medio
2 d 15 h
PR fusionados (30 d)
61

Preparar el entorno

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Más de resend/react-email

Todos los issues de resend/react-email

Issues similares

Más issues de TypeScript

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.