Maizzle vs MJML: ¿qué framework conviene para construir sus emails?
Por Mara Levin · Actualizado el 7 de octubre de 2026 · documentación y precios revisados ese día
Los dos son gratuitos y los dos convierten un código fuente legible en HTML apto para email. Uno le pide aprender un vocabulario nuevo de etiquetas; el otro, escribir componentes Vue y clases de Tailwind.
Respuesta corta
Elija Maizzle si su equipo ya escribe Vue y Tailwind, quiere condicionales y bucles dentro de las plantillas y prefiere un servidor de desarrollo que avise de CSS no admitido mientras se escribe. Elija MJML si los emails los compilan personas o servicios ajenos al ecosistema JavaScript, si le basta un vocabulario reducido de secciones y columnas ya preparadas, o si una herramienta que ya utiliza acepta MJML (Loops lo hace). Las licencias no inclinan la balanza en este caso, porque ninguno de los dos cobra nada.
De un vistazo
| Pregunta | Maizzle | MJML |
|---|---|---|
| Qué se escribe | Componentes de archivo único de Vue con estilos de Tailwind CSS 4 | Etiquetas de estilo XML: mj-section, mj-column, mj-text |
| Cómo empezar un proyecto | npx maizzle new y después npx maizzle serve | npm install mjml, o el editor en línea |
| Compilación | npx maizzle build, o build() / render() desde Node | mjml file.mjml -o dist/file.html, o mjml2html en Node |
| Lógica dentro de la plantilla | Vue: v-if, v-for, <script setup> | Ninguna; las etiquetas de plantilla van en mj-raw y se ejecutan en un paso posterior |
| Componentes incluidos | Más de 30, desde Button hasta códigos QR | El conjunto estándar más componentes de la comunidad |
| Uso fuera de Node | Solo compilación con Node | Ports y bindings para otros lenguajes |
| Coste de uso | Sin precios de plan publicados | Licencia MIT, según las preguntas frecuentes de MJML |
El mismo email de bienvenida en ambos
La documentación de Maizzle incluye una página de migración para quien viene de MJML, con el mismo email escrito de las dos maneras. Los dos bloques siguientes proceden de ella: la guía de Maizzle para usuarios de MJML. La misma página trae una tabla de equivalencias de componentes, que es la forma más rápida de medir cuánto se separan en realidad ambos vocabularios.
MJML
<mjml>
<mj-head>
<mj-title>Welcome to Acme</mj-title>
<mj-preview>Let's get you set up.</mj-preview>
<mj-attributes>
<mj-all font-family="Helvetica, Arial, sans-serif" />
<mj-text color="#475569" font-size="16px" />
</mj-attributes>
</mj-head>
<mj-body background-color="#ffffff">
<mj-section>
<mj-column>
<mj-text font-size="24px" color="#0f172a">Hi {{ name }}</mj-text>
<mj-text>Thanks for signing up. Click below to verify your email.</mj-text>
<mj-button href="https://example.com/verify" background-color="#2563eb">
Verify email
</mj-button>
</mj-column>
</mj-section>
</mj-body>
</mjml> Maizzle
<script setup>
defineProps({ name: String })
useHead({ title: 'Welcome to Acme' })
</script>
<template>
<Html>
<Head />
<Preheader>Let's get you set up.</Preheader>
<Tailwind>
<Body class="text-gray-600 text-base bg-white font-sans">
<Container class="max-w-lg">
<Text class="text-2xl text-gray-950">Hi {{ name }}</Text>
<Text>Thanks for signing up. Click below to verify your email.</Text>
<Button href="https://example.com/verify" class="bg-blue-600 text-white">
Verify email
</Button>
</Container>
</Body>
</Tailwind>
</Html>
</template> Llaman la atención tres cosas. El estilo deja de ir en atributos de cada etiqueta y pasa a clases de Tailwind. La cabecera de la página se arma con useHead() y un componente Preheader en lugar de mj-title y mj-preview. Y {{ name }} ya no es un marcador que se rellena más tarde: en Maizzle es una prop de Vue, de modo que el mismo archivo puede renderizarse para cualquier nombre que se le pase, con todas las herramientas de Vue (condiciones, bucles, valores calculados) a su alrededor.
Dónde se nota la diferencia en el trabajo diario
Contenido dinámico
MJML no tiene variables propias. La documentación de MJML indica que la sintaxis de plantillas debe ir dentro de mj-raw y advierte de que la minificación puede tropezar con caracteres como < dentro de esas etiquetas, algo que se resuelve con comentarios htmlmin:ignore. En la práctica se compila primero y después se pasa Handlebars, Liquid o código propio sobre el HTML resultante. Maizzle renderiza sus componentes Vue mediante renderizado en servidor, así que la lógica se ejecuta durante la compilación, y esa misma compilación puede entregar además una versión en texto plano.
Fragmentos compartidos
MJML ofrece mj-include, con una trampa que conviene conocer antes de adoptarlo: los includes se ignoran en silencio salvo que se active expresamente ignoreIncludes: false en Node o --config.allowIncludes true en la línea de comandos. Si la cabecera desaparece del resultado, esa es la primera comprobación. El equivalente en Maizzle es un componente de Vue; la guía de migración lo muestra como un pequeño componente Header colocado dentro del cuerpo.
import mjml2html from 'mjml'
async function compile(source) {
const { html, errors } = await mjml2html(source, { ignoreIncludes: false })
return html
} El ejemplo sigue la llamada asíncrona a mjml2html y la opción ignoreIncludes que aparecen en la documentación de MJML. Cuando los includes usan rutas relativas, esa misma página de la documentación pasa además un filePath para que MJML sepa desde dónde resolverlas.
Servidor de desarrollo y comprobaciones
El servidor de desarrollo de Maizzle ofrece vista previa en vivo, cambio de tamaño de dispositivo, emulación del modo oscuro y una pestaña de comprobaciones. Estas son de dos tipos: avisos de compatibilidad construidos con datos de caniemail.com y reglas de lint, como un Button sin href o una imagen sin alt. De forma predeterminada apuntan a Gmail, Apple Mail, Outlook y Yahoo!. Las herramientas de MJML son más ligeras: modo de vigilancia en la CLI, un nivel de validación configurable (strict, soft o skip) y plugins para editores. Ninguna de las dos sustituye a las capturas en clientes reales, y la propia página de compatibilidad de Maizzle lo reconoce.
Outlook y otros clientes complicados
Ambos frameworks encapsulan los trucos de tablas y comentarios condicionales para que no haya que escribirlos a mano. El Button de Maizzle tiene props como msoPt, msoPb y msoPx para el relleno en el Outlook clásico y un interruptor outlookFallback; además incluye los componentes Outlook, NotOutlook y OutlookBg (imágenes de fondo en VML) para los casos en que hay que apuntar directamente a ese cliente. La documentación de MJML es más tajante con un límite: mj-button no es totalmente pulsable en algunos clientes por su compatibilidad limitada. Los dos enfoques son válidos; lo importante es pulsar las esquinas del botón en una vista previa real de Outlook.
Dónde vive el proyecto
Maizzle puede ser un repositorio propio o un plugin de Vite dentro de una aplicación. La documentación menciona Laravel, Nuxt, SvelteKit y Astro, y describe el plugin como una instancia de Maizzle con su propio servidor de desarrollo junto al suyo, que compila los emails después de vite build. MJML queda fuera de su compilación: se invoca la CLI o mjml2html donde convenga, y por eso encaja en equipos de Rails, Django o .NET sin ninguna cadena de herramientas de frontend.
Cómo sacar el HTML
El resultado compilado es solo la mitad del trabajo. Maizzle documenta recetas de despliegue para Nodemailer, SendGrid, Mailgun, Postmark, Resend, AWS SES y Cloudflare. La de Resend, tomada de su página de despliegue, renderiza una plantilla y la envía en pocas líneas:
import { Resend } from 'resend'
import { render } from '@maizzle/framework'
const resend = new Resend(process.env.RESEND_API_KEY)
const { html, plaintext } = await render('emails/welcome.vue')
await resend.emails.send({
from: 'hello@yourdomain.com',
to: 'user@example.com',
subject: 'Welcome',
html,
text: plaintext,
}) Para una compilación previa que se ejecuta con antelación, la forma programática es esta:
import { build } from '@maizzle/framework'
const { files } = await build({
content: ['emails/**/*.vue'],
output: { path: 'dist' },
}) Lo que cuesta el resto de la pila alrededor de dos frameworks gratuitos
El framework es la parte barata. Pesan dos partidas de la factura: las vistas previas y el envío. En su página de precios, Email on Acid lista Basic a 99 $ al mes con 1.000 vistas previas y Premium a 199 $ con 2.000, y cobra 0,15 $ por cada vista previa adicional. Cada captura de un cliente o dispositivo cuenta como una, así que una prueba en 50 clientes consume 50: Basic alcanza para unas 20 pasadas completas al mes y Premium para unas 40. Si usted reconstruye un email cinco veces antes de enviarlo, ese presupuesto se agota enseguida, y eso favorece al framework con el ciclo de respuesta más corto, sea cual sea.
Para el envío, la página de precios de Resend lista un plan Free de 0 $ con 3.000 emails al mes (100 al día) y Pro a 20 $ con 50.000. La salida de cualquiera de los dos frameworks funciona con él, y la documentación de Maizzle muestra cómo conectarlos paso a paso. Para comparar otros servicios de envío, las páginas Resend vs Postmark y Postmark vs SendGrid ponen las cifras una al lado de otra.
Elija Maizzle si…
- Diseñadores y desarrolladores ya comparten una configuración de Tailwind y quiere que el email la siga.
- Las plantillas necesitan lógica de verdad: cambio de idioma, filas repetidas a partir de datos, bloques opcionales.
- Desea que el framework avise de CSS no admitido antes de abrir un servicio de vistas previas.
- Los emails viven junto a una aplicación Vite (Laravel, Nuxt, SvelteKit, Astro) y comparten componentes con ella.
Elija MJML si…
- Su backend no es JavaScript, o varios servicios deben compilar el mismo código fuente.
- Prefiere un vocabulario corto en el que el diseño se reduce a
mj-sectionymj-column, y no quiere pensar en Tailwind en absoluto. - Una plataforma que usa acepta MJML directamente. Loops, por ejemplo, permite subir su propio MJML en lugar de usar su editor.
- Personas que no son desarrolladores de frontend necesitan leer y revisar las plantillas.
Pasar de uno a otro
Ir de MJML a Maizzle es el sentido mejor documentado, ya que Maizzle aporta la tabla de equivalencias. Reconstruya primero un email de poco riesgo, como el de restablecer contraseña, envíe las dos versiones por las mismas vistas previas de clientes y compare las capturas. El camino inverso obliga a aplanar la lógica de Vue en marcadores, así que conviene decidir de antemano dónde vivirán después los bloques condicionales. Para otras parejas, véanse MJML vs React Email y React Email vs Maizzle; y para los límites de CSS que hay detrás de todo esto, lea CSS en el email y la guía de compatibilidad con clientes.
Preguntas frecuentes
¿Maizzle sigue siendo «tablas HTML más Tailwind»?
No según su documentación actual. Maizzle se presenta como un framework para crear emails HTML con Vue y Tailwind CSS, las plantillas son componentes de archivo único de Vue y la documentación está versionada como 6.x. Los artículos antiguos que muestran tablas escritas a mano con clases de utilidad describen un flujo de trabajo anterior, así que conviene comprobar a qué versión se refiere un tutorial antes de copiar su código.
¿Puedo pasar una biblioteca de MJML ya existente a Maizzle?
No hay un conversor de un solo clic, pero Maizzle publica una tabla de equivalencias. mj-section pasa a ser Section, mj-column pasa a Column, mj-button pasa a Button, mj-preview pasa a Preheader y mj-include se convierte en un componente Vue propio. Empiece por los emails que usan menos atributos personalizados y compare las vistas previas en clientes reales antes de migrar el resto.
¿Cuál requiere menos configuración en un equipo que no usa Node?
MJML. Su documentación enumera ports y bindings para varios otros lenguajes, y también se puede compilar una vez en integración continua y entregar el HTML a un backend escrito en cualquier tecnología. Maizzle da por hecho una compilación con Node y Vue, ya sea como proyecto independiente o como plugin de Vite dentro de una aplicación existente.
¿Alguno de los dos prueba mis emails en clientes reales?
No. Maizzle ejecuta comprobaciones de compatibilidad y de lint en su servidor de desarrollo con datos de caniemail.com, y recomienda hacer pruebas de renderizado en clientes reales antes de enviar. MJML valida el marcado según sus propias reglas. Para obtener capturas de clientes de verdad sigue haciendo falta un servicio de vistas previas como Email on Acid o Litmus.