Maizzle o MJML: quale framework scegliere per costruire le proprie email?

Di Mara Levin · Aggiornato il 7 ottobre 2026 · documentazione e prezzi verificati in quella data

Entrambi sono gratuiti ed entrambi trasformano un sorgente leggibile in HTML adatto ai client di posta. Il primo chiede di scrivere componenti Vue e classi Tailwind, il secondo di imparare un vocabolario di tag tutto suo.

La risposta breve

Conviene Maizzle se il team scrive già Vue e Tailwind, vuole condizioni e cicli dentro i template e apprezza un server di sviluppo che segnala il CSS non supportato mentre si lavora. Conviene MJML se le email vengono compilate da persone o servizi che non vivono nel mondo JavaScript, se si preferisce un piccolo vocabolario di sezioni e colonne già pronte, oppure se uno strumento già in uso accetta MJML (Loops lo fa). A decidere non sono le licenze, perché nessuno dei due ha un costo.

In sintesi

Domanda Maizzle MJML
Che cosa si scriveComponenti single-file di Vue, con stile Tailwind CSS 4Tag in stile XML: mj-section, mj-column, mj-text
Avviare un progettonpx maizzle new, poi npx maizzle servenpm install mjml, oppure l'editor online
Compilazionenpx maizzle build, oppure build() / render() da Nodemjml file.mjml -o dist/file.html, oppure mjml2html in Node
Logica nel templateVue: v-if, v-for, <script setup>Nessuna; i tag di templating vanno in mj-raw e vengono eseguiti in un passaggio successivo
Componenti integratiPiù di 30, dal Button ai codici QRIl set standard più i componenti della community
Uso fuori da NodeSolo build NodePort e binding per altri linguaggi
Costo d'usoNessun prezzo di piano pubblicatoLicenza MIT, secondo le FAQ di MJML

La stessa email di benvenuto nei due formati

La documentazione di Maizzle contiene una pagina di migrazione per chi arriva da MJML, con la stessa email scritta nei due modi. I due blocchi qui sotto sono ripresi da quella pagina: la guida di Maizzle per chi usa MJML. La guida include anche la tabella dei componenti, che è il modo più rapido per capire quanto siano distanti i due vocabolari.

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>

Saltano all'occhio tre cose. Lo stile passa dagli attributi di ogni tag alle classi Tailwind. L'intestazione della pagina si compone con useHead() e con un componente Preheader, al posto di mj-title e mj-preview. Infine {{ name }} non è più un segnaposto da riempire in un secondo momento: in Maizzle è una prop di Vue, quindi lo stesso file può produrre l'email per qualunque nome gli venga passato, con tutti gli strumenti di Vue (condizioni, cicli, valori calcolati) a disposizione.

Dove i due approcci si differenziano nel lavoro di tutti i giorni

Contenuti dinamici

MJML non ha variabili proprie. La documentazione di MJML indica di inserire la sintassi di templating dentro mj-raw e avverte che la minificazione può inciampare su caratteri come < in quei tag, un problema che si aggira con i commenti htmlmin:ignore. Nella pratica si compila prima, poi si passa Handlebars, Liquid o il proprio codice sull'HTML ottenuto. Maizzle, invece, renderizza i componenti Vue con il rendering lato server: la logica gira durante la build, e la build può produrre anche la versione in testo semplice.

Parti condivise

MJML offre mj-include, con un'insidia da conoscere prima di adottarlo: gli include vengono ignorati in silenzio, a meno di attivarli con ignoreIncludes: false in Node oppure con --config.allowIncludes true da riga di comando. Se l'intestazione sparisce dall'output, è la prima cosa da controllare. L'equivalente in Maizzle è un componente Vue: la guida di migrazione lo mostra come un piccolo componente Header collocato nel body.

import mjml2html from 'mjml'

async function compile(source) {
  const { html, errors } = await mjml2html(source, { ignoreIncludes: false })
  return html
}

L'esempio segue la chiamata asincrona a mjml2html e l'opzione ignoreIncludes descritte nella documentazione di MJML. Quando gli include usano percorsi relativi, la stessa pagina di documentazione passa anche un filePath, in modo che MJML sappia da dove risolverli.

Server di sviluppo e controlli

Il server di sviluppo di Maizzle offre anteprima dal vivo, ridimensionamento per dispositivo, emulazione della modalità scura e una scheda Checks. I controlli sono di due tipi: avvisi di compatibilità costruiti sui dati di caniemail.com e regole di lint, per esempio un Button senza href o un'immagine senza alt. Per impostazione predefinita i bersagli sono Gmail, Apple Mail, Outlook e Yahoo!. Gli strumenti di MJML sono più leggeri: una modalità watch nella CLI, un livello di validazione (strict, soft o skip) e plugin per gli editor. Nessuno dei due sostituisce gli screenshot dei client reali, e la pagina sulla compatibilità di Maizzle lo dice espressamente.

Outlook e gli altri client problematici

Entrambi i framework racchiudono i trucchi con le tabelle e i commenti condizionali, così da non doverli scrivere a mano. Il Button di Maizzle ha prop come msoPt, msoPb e msoPx per il padding nell'Outlook classico, più un interruttore outlookFallback, e ci sono i componenti Outlook, NotOutlook e OutlookBg (immagini di sfondo VML) per i casi in cui serve prendere di mira quel client in modo diretto. La documentazione di MJML è più schietta su un limite: mj-button non è cliccabile su tutta la superficie in alcuni client, per via del supporto limitato. Entrambi gli approcci vanno bene; ciò che conta è cliccare gli angoli del pulsante in un'anteprima reale di Outlook.

Dove vive il progetto

Maizzle può essere un repository a parte oppure un plugin Vite dentro un'applicazione. La documentazione cita Laravel, Nuxt, SvelteKit e Astro e descrive il plugin come un'istanza di Maizzle che gira nel proprio server di sviluppo accanto a quello dell'app e compila le email dopo vite build. MJML resta fuori dalla build dell'applicazione: si richiama la CLI o mjml2html dove si preferisce, ed è per questo che si adatta a chi lavora con Rails, Django o .NET senza alcuna toolchain frontend.

Portare l'HTML a destinazione

L'output compilato è solo metà del lavoro. Maizzle documenta ricette di distribuzione per Nodemailer, SendGrid, Mailgun, Postmark, Resend, AWS SES e Cloudflare. Quella per Resend, tratta dalla relativa pagina di deploy, renderizza un template e lo invia in poche righe:

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,
})

Per una build da eseguire in anticipo, la forma programmatica è questa:

import { build } from '@maizzle/framework'

const { files } = await build({
  content: ['emails/**/*.vue'],
  output: { path: 'dist' },
})

Quanto costa lo stack intorno a due framework gratuiti

Il framework è la parte economica. A pesare sono due voci: le anteprime e l'invio. Sulla propria pagina dei prezzi Email on Acid elenca il piano Basic a $99 al mese per 1.000 anteprime e il Premium a $199 per 2.000, con un sovrapprezzo di 0,15 $ per ogni anteprima in più. Ogni screenshot di un client o di un dispositivo conta come un'anteprima, quindi un test su 50 client ne consuma 50: Basic copre circa 20 esecuzioni complete al mese, Premium circa 40. Se un'email viene ricostruita cinque volte prima dell'invio, quel budget si esaurisce in fretta, ed è un argomento a favore del framework con il ciclo di feedback più rapido, quale che sia.

Per l'invio, la pagina dei prezzi di Resend indica un piano Free a $0 con 3.000 email al mese (100 al giorno) e un piano Pro a $20 con 50.000. L'output di entrambi i framework funziona con Resend, e la documentazione di Maizzle mostra come fare. Per confrontare altri servizi di invio, le pagine Resend vs Postmark e Postmark vs SendGrid mettono i numeri uno accanto all'altro.

Pagina dei prezzi di Resend, catturata a ottobre 2026
Pagina dei prezzi di Resend al 7 ottobre 2026. Fonte: https://resend.com/pricing

Scegliere Maizzle se…

  • Designer e sviluppatori condividono già una configurazione Tailwind e si vuole che anche le email la seguano.
  • I template richiedono vera logica: cambio di lingua, righe ripetute a partire da dati, blocchi opzionali.
  • Si desidera che sia il framework a segnalare il CSS non supportato, prima ancora di aprire un servizio di anteprima.
  • Le email stanno accanto a un'app Vite (Laravel, Nuxt, SvelteKit, Astro) e ne condividono i componenti.

Scegliere MJML se…

  • Il backend non è in JavaScript, oppure più servizi devono compilare lo stesso sorgente.
  • Si preferisce un vocabolario breve in cui il layout è fatto di mj-section e mj-column, senza dover pensare a Tailwind.
  • Una piattaforma in uso accetta MJML direttamente: Loops, per esempio, permette di caricare il proprio MJML al posto del suo editor.
  • I template devono essere letti e rivisti anche da chi non è uno sviluppatore front-end.

Passare dall'uno all'altro

Da MJML a Maizzle è la direzione meglio documentata, perché Maizzle fornisce la tabella dei componenti. Si ricostruisce per prima un'email a basso rischio, come il reset della password, si inviano entrambe le versioni alle stesse anteprime dei client e si confrontano gli screenshot. Nell'altro senso occorre appiattire la logica di Vue in segnaposto, quindi conviene decidere fin dall'inizio dove andranno a finire i blocchi condizionali. Per altri accoppiamenti si vedano MJML vs React Email e React Email vs Maizzle; per i limiti del CSS che stanno dietro a tutto questo, la guida al CSS nelle email e quella sulla compatibilità dei client.

Domande frequenti

Maizzle è ancora «tabelle HTML più Tailwind»?

Non secondo la documentazione attuale. Maizzle si presenta come un framework per costruire email HTML con Vue e Tailwind CSS, i template sono componenti single-file di Vue e la documentazione è versionata come 6.x. Gli articoli più vecchi, che mostrano tabelle scritte a mano con classi di utilità, descrivono un flusso di lavoro precedente: prima di copiare il codice di un tutorial conviene verificare a quale versione si riferisce.

Si può portare una libreria MJML già esistente su Maizzle?

Non esiste un convertitore a un clic, ma Maizzle pubblica una tabella di corrispondenze tra i componenti. mj-section diventa Section, mj-column diventa Column, mj-button diventa Button, mj-preview diventa Preheader e mj-include diventa un componente Vue personalizzato. Si comincia dalle email con meno attributi personalizzati e si confrontano le anteprime nei client prima di spostare le altre.

Quale dei due richiede meno configurazione per un team che non usa Node?

MJML. La sua documentazione elenca port e binding per diversi altri linguaggi, e si può compilare una volta in CI e consegnare l'HTML a un backend scritto in qualsiasi linguaggio. Maizzle presuppone una build Node con Vue, come progetto a sé stante oppure come plugin Vite dentro un'applicazione esistente.

Uno dei due prova le email nei client di posta reali?

No. Maizzle esegue controlli di compatibilità e di lint nel server di sviluppo usando i dati di caniemail.com, e raccomanda di fare i test di rendering nei client reali prima dell'invio. MJML convalida il markup secondo le proprie regole. Per ottenere veri screenshot dei client serve comunque un servizio di anteprima come Email on Acid o Litmus.