# Editores y API de MJML

> Crea plantillas y campañas adaptables con MJML, una función en alfa abierta al equipo de Emailit. Los editores Visual y Code, los documentos guardados, la validación, Temple en MJML, la colaboración en directo y la API de MJML.

[MJML](https://mjml.io) es un lenguaje de marcado para emails adaptables. Escribes secciones, columnas y componentes como `<mj-text>` y `<mj-button>`, y MJML los compila en un HTML que se muestra de forma coherente en todos los clientes de correo. En Emailit, MJML puede ser el origen de una plantilla o de una campaña: lo escribes en los editores del panel o lo envías con la API, y Emailit lo valida y compila el HTML.

> **MJML está en alfa:** MJML está en alfa y solo está abierto al equipo de Emailit mientras lo probamos. Los espacios de trabajo de los clientes todavía no ven los editores MJML, y las peticiones a la API que crean o cambian plantillas MJML, o que llaman a los endpoints de MJML, devuelven `403` con `error: "mjml_alpha"`. Esta página describe cómo funciona MJML para que puedas planificar su uso. Cualquiera puede seguir enviando las plantillas y campañas creadas con MJML.

## Descripción general

- **Plantillas**: `editor: "mjml"` con el MJML en `source`. Consulta [Crear una plantilla](/es/docs/api-reference/templates/create/).
- **Campañas**: `content_type: "mjml"` con el MJML en `content`. Consulta [Campañas](#campaigns).
- **Automatizaciones**: el paso **Send email** envía una plantilla MJML como cualquier otra plantilla. Consulta [Automatizaciones](#automations).
- **Endpoints de MJML**: [Validar MJML](/es/docs/api-reference/mjml/validate/), [Renderizar MJML](/es/docs/api-reference/mjml/render/) y [Obtener la referencia de MJML](/es/docs/api-reference/mjml/reference/).

### Quién puede usar MJML

Durante la fase alfa, MJML solo está disponible para los administradores de la plataforma de Emailit. El rol Admin de un espacio de trabajo no basta.

| Dónde | Equipo de Emailit | Todos los demás |
| --- | --- | --- |
| Panel | Editores MJML, importación de MJML, **Edit with AI** y colaboración en directo | Sin editores MJML. Una plantilla o campaña MJML muestra un aviso, no se puede abrir en un editor y se sigue enviando. |
| API | Plantillas MJML, campañas MJML y los endpoints de MJML | `403` con `error: "mjml_alpha"`. El `content_type: "mjml"` de una campaña sigue siendo una simple etiqueta, como antes de la fase alfa. Consulta [Campañas](#campaigns). |
| Claves de API | Ninguna. Las claves de API pertenecen a un espacio de trabajo, no a una persona. | `403` con `error: "mjml_alpha"` |
| Servidor MCP | Las herramientas de MJML y los parámetros de MJML de las herramientas de plantillas y campañas | No aparecen |

Cualquiera puede seguir cambiando el nombre de las plantillas y campañas MJML, publicándolas, exportándolas, enviándolas y eliminándolas. Duplicar una plantilla MJML crea una plantilla MJML nueva, así que requiere acceso a MJML.

### Versión de MJML

Emailit compila todo el MJML con **MJML 5.4.1**, tanto en el servidor como en la vista previa en directo de los editores. La validación comprueba las etiquetas, los atributos y los valores de los atributos según esa versión. [Obtener la referencia de MJML](/es/docs/api-reference/mjml/reference/) devuelve la versión y todos los componentes y atributos que admite.

### Editores

El panel tiene dos editores MJML. Los dos tienen versiones y los dos son versiones alfa `0.x`.

| Editor | ID | Versión | Descripción |
| --- | --- | --- | --- |
| MJML Visual Editor | `mjml-visual` | 0.2.0 (alfa) | Arrastrar y soltar sobre el email renderizado, con todos los componentes y atributos de MJML |
| MJML Code Editor | `mjml-code` | 0.2.0 (alfa) | MJML con autocompletado, validación en línea y una vista previa en directo para escritorio y móvil |

Los dos editores guardan la plantilla con `editor: "mjml"`. El documento guardado registra qué editor, y qué versión de ese editor, lo guardó por última vez. Varios compañeros pueden editar la misma plantilla o campaña a la vez. Consulta [Edición conjunta](#editing-together).

## Formatos de origen

Allí donde Emailit acepta MJML (el `source` de una plantilla, el `content` de una campaña y el campo `source` de los endpoints de MJML), puedes enviar cualquiera de estos formatos:

| Formato | Ejemplo |
| --- | --- |
| Marcado MJML | Una cadena que empieza por `<mjml>`. Se admiten una declaración XML o comentarios iniciales. |
| MJML JSON | El formato JSON propio de MJML, como objeto o como cadena JSON: `{ "tagName": "mjml", "attributes": {}, "children": [ … ] }`. Las etiquetas finales (ending tags), como `mj-text`, llevan su HTML en `content`. |
| Documento MJML de Emailit | El envoltorio que guarda Emailit (abajo), como objeto o como cadena JSON |

Cualquier otra cosa se rechaza con `document.unrecognized`. Un origen de más de 2 MB se rechaza con `document.too-large`.

### El documento guardado

Emailit guarda el MJML en un envoltorio con versiones. Es el `source` de la plantilla y el `content` de la campaña:

```json
{
  "kind": "emailit/mjml",
  "schema_version": 1,
  "mjml_version": "5.4.1",
  "editor": "api",
  "editor_version": null,
  "format": "markup",
  "content": "<mjml>\n  <mj-body>\n    …\n  </mj-body>\n</mjml>"
}
```

| Campo | Descripción |
| --- | --- |
| `kind` | Siempre `emailit/mjml`. |
| `schema_version` | La versión de la estructura del envoltorio. Actualmente, `1`. |
| `mjml_version` | La versión de MJML para la que está escrito el contenido. Emailit le asigna la versión con la que lo compiló. |
| `editor` | Lo que escribió el documento por última vez: `mjml-visual`, `mjml-code`, `ai` (**Edit with AI**) o `api` (la API, las herramientas MCP y las importaciones de archivos). |
| `editor_version` | La versión de ese editor, o `null`. |
| `format` | `markup`: `content` es marcado MJML, guardado tal como se escribió, con los comentarios y el formato. `json`: `content` es MJML JSON. |
| `content` | El MJML. |

Lo que envías decide el formato: el marcado se guarda como `markup` y el MJML JSON como `json`. Los dos se registran como `editor: "api"`. Un envoltorio que envíes conserva su `editor` y su `editor_version`.

Las respuestas de la API devuelven `source` como este envoltorio, serializado como cadena JSON, y puedes volver a enviarlo sin cambios. Las respuestas también incluyen un objeto `mjml` con las versiones del envoltorio:

```json
"mjml": {
  "mjml_version": "5.4.1",
  "schema_version": 1,
  "editor": "api",
  "editor_version": null,
  "format": "markup"
}
```

El panel abre un documento en el editor que lo guardó por última vez. Los documentos escritos con la API se abren en el Code Editor cuando `format` es `markup` y en el Visual Editor cuando es `json`.

## Compilar y guardar

En las plantillas y campañas MJML, Emailit se encarga del HTML:

- Al crear y al actualizar, Emailit valida el MJML y lo compila. El HTML compilado se guarda como el `html` de la plantilla, y se ignora cualquier `html` que envíes.
- Los envíos usan el HTML guardado. Las etiquetas de Temple se quedan en él y se renderizan para cada destinatario en el momento del envío.
- Actualizar solo otros campos, como `name` o `subject`, no vuelve a compilar.
- `text` no se genera a partir del MJML. Envía tú `text` si quieres una parte de texto plano.
- Cambiar una plantilla existente a `editor: "mjml"` sin enviar `source` compila el `source` guardado de la plantilla, que entonces debe ser MJML.

El HTML se compila al guardar, así que el HTML de una plantilla existente solo cambia cuando se vuelve a guardar.

```bash
curl https://api.emailit.com/v2/templates \
  -H "Authorization: Bearer your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Welcome",
    "alias": "welcome",
    "subject": "Welcome, {{first_name|\"there\"}}",
    "editor": "mjml",
    "source": "<mjml><mj-head><mj-title>Welcome</mj-title><mj-preview>Your account is ready</mj-preview></mj-head><mj-body><mj-section><mj-column><mj-text>Hi {{first_name|\"there\"}}, welcome aboard.</mj-text><mj-button href=\"{{activation_url}}\">Activate account</mj-button></mj-column></mj-section></mj-body></mjml>"
  }'
```

Después, envíala como cualquier otra plantilla con [Enviar un email](/es/docs/api-reference/emails/send/): `"template": "welcome"` y un objeto `variables`.

## Validación

Cada guardado ejecuta las mismas comprobaciones que [Validar MJML](/es/docs/api-reference/mjml/validate/):

- La sintaxis XML: etiquetas sin cerrar o mal emparejadas y atributos mal formados (`xml.*`)
- La estructura, los atributos y los valores de los atributos de MJML para MJML 5.4.1 (`mjml.*`)
- La sintaxis de Temple y que los bloques `{{#if}}` estén equilibrados (`temple.*`)
- El formato y las versiones del origen (`document.*`), y el propio compilador (`compiler.*`)

Cada hallazgo es un diagnóstico con una gravedad:

| Gravedad | Efecto |
| --- | --- |
| `error` | El MJML se rechaza. Las plantillas y campañas no se guardan. |
| `warning` | Se guarda. Probablemente es un error: no hay `<mj-title>`, hay texto fuera de un componente, un bloque condicional atraviesa varios componentes o el HTML supera el límite de recorte de 102 KB de Gmail. |
| `info` | Se guarda. Una sugerencia o una nota: no hay `<mj-preview>`, una imagen no tiene `alt` o el documento está escrito para una versión anterior de MJML. |

Un diagnóstico tiene estos campos. Los campos que no aplican se omiten.

| Campo | Descripción |
| --- | --- |
| `severity` | `error`, `warning` o `info` |
| `code` | Un código estable y legible por máquinas, por ejemplo `mjml.invalid-child` |
| `message` | Una explicación legible, a menudo con una solución («Did you mean color?») |
| `line`, `column` | La posición en el marcado, empezando por 1. Solo en orígenes de marcado. |
| `tag` | El elemento al que se refiere el diagnóstico |
| `attribute` | El atributo, si lo hay |
| `path` | La ruta de índices de hijos desde la raíz `<mjml>`. `[0, 1]` es el segundo hijo del primer hijo. |

### Respuesta de error

Guardar una plantilla o campaña con diagnósticos de error devuelve `422`. Con este origen:

```xml
<mjml>
  <mj-body>
    <mj-section>
      <mj-column>
        <mj-text colour="#333333">Hi {{first_name|"there"}}</mj-text>
        <mj-button href="{{cta_url}}">{{#if trial}}Start trial</mj-button>
      </mj-column>
    </mj-section>
  </mj-body>
</mjml>
```

la respuesta es:

```json
{
  "message": "The MJML is not valid.",
  "errors": {
    "source": [
      "Line 5: <mj-text> has no attribute colour. Did you mean color?",
      "Line 6: {{#if trial}} is never closed with {{/if}}."
    ]
  },
  "diagnostics": [
    {
      "severity": "error",
      "code": "mjml.unknown-attribute",
      "message": "<mj-text> has no attribute colour. Did you mean color?",
      "line": 5,
      "column": 18,
      "tag": "mj-text",
      "attribute": "colour",
      "path": [0, 0, 0, 0]
    },
    {
      "severity": "warning",
      "code": "mjml.missing-title",
      "message": "Add an <mj-title> to <mj-head>; clients and screen readers use it.",
      "line": 1,
      "column": 2,
      "tag": "mjml",
      "path": []
    },
    {
      "severity": "info",
      "code": "mjml.missing-preview",
      "message": "Add an <mj-preview> to control the inbox preview text.",
      "line": 1,
      "column": 2,
      "tag": "mjml",
      "path": []
    },
    {
      "severity": "error",
      "code": "temple.unclosed-if",
      "message": "{{#if trial}} is never closed with {{/if}}.",
      "line": 6,
      "column": 39,
      "tag": "mj-button",
      "path": [0, 0, 0, 1]
    }
  ]
}
```

- `errors.source` (`errors.content` en las campañas) muestra hasta cinco mensajes de error, con su línea cuando se conoce.
- `diagnostics` muestra todos los diagnósticos, incluidos los de advertencia y los informativos.
- Un origen ausente o vacío devuelve `422` con `"message": "Validation failed"`, `"errors": { "source": ["The source field is required for MJML."] }` y un array `diagnostics` vacío.

[Validar MJML](/es/docs/api-reference/mjml/validate/) ejecuta las mismas comprobaciones sin guardar y devuelve `200` con `valid: false` en lugar de `422`.

### Códigos de diagnóstico

**XML** (orígenes de marcado)

| Código | Gravedad | Significado |
| --- | --- | --- |
| `xml.unclosed-tag` | error | Un elemento no se cierra nunca. |
| `xml.unexpected-closing-tag` | error | Una etiqueta de cierre no corresponde a ningún elemento abierto. |
| `xml.malformed-closing-tag` | error | No se puede leer una etiqueta de cierre. |
| `xml.unterminated-tag` | error | Una etiqueta de apertura no tiene el `>` de cierre. |
| `xml.unterminated-attribute` | error | El valor de un atributo no tiene la comilla de cierre. |
| `xml.missing-attribute-value` | error | `name=` no tiene valor. |
| `xml.invalid-attribute` | error | Un carácter inesperado dentro de una etiqueta. |
| `xml.duplicate-attribute` | error | El mismo atributo dos veces en un elemento. Se usa el primero. |
| `xml.unterminated-comment` | error | Un comentario no tiene `-->`. |
| `xml.unterminated-cdata` | error | Una sección CDATA no tiene `]]>`. |
| `xml.unexpected-character` | error | Un `<` suelto fuera de una etiqueta final. |
| `xml.multiple-roots` | error | Más de un elemento raíz. |
| `xml.text-outside-root` | error | Texto fuera de `<mjml>`. |
| `mjml.missing-root` | error | El documento está vacío. |
| `xml.unquoted-attribute` | warning | El valor de un atributo sin comillas. |
| `xml.stray-text` | warning | Texto entre elementos, fuera de cualquier componente de contenido. MJML lo ignora. |
| `xml.unexpected-declaration` | warning | Una declaración después del inicio de `<mjml>`. |

**MJML**

| Código | Gravedad | Significado |
| --- | --- | --- |
| `mjml.unknown-tag` | error | No es un elemento de MJML 5.4.1. Incluye una sugerencia «Did you mean…?» cuando hay uno parecido. |
| `mjml.unknown-attribute` | error | El elemento no tiene ese atributo. En el propio `<mjml>`, es una advertencia. |
| `mjml.invalid-attribute-value` | error | Un valor del tipo incorrecto: no es un color, una unidad ni un valor permitido. |
| `mjml.invalid-child` | error | El elemento no se permite dentro de su padre. |
| `mjml.invalid-root` | error | El elemento raíz no es `<mjml>`. |
| `mjml.missing-body` | error | No hay `<mj-body>`. |
| `mjml.duplicate-body` | error | Hay más de un `<mj-body>`. |
| `mjml.include-not-supported` | error | `<mj-include>` no se admite. |
| `mjml.missing-attribute` | error o warning | Falta un atributo obligatorio. Es un error en `name` y `href` de `<mj-font>`, `name` de `<mj-class>`, `path` de `<mj-selector>` y `name` de `<mj-html-attribute>`. Es una advertencia en el `src` de una imagen y en el `width` de `<mj-breakpoint>`. |
| `mjml.missing-title` | warning | No hay `<mj-title>` en `<mj-head>`. |
| `mjml.empty-title` | warning | `<mj-title>` está vacío. |
| `mjml.duplicate-head` | warning | Hay más de un `<mj-head>`. |
| `mjml.ignored-content` | warning | Texto dentro de un elemento que no admite contenido. |
| `mjml.ignored-children` | warning | Elementos hijos dentro de un elemento que solo admite contenido. |
| `mjml.column-widths` | warning | Los anchos de las columnas de una sección o un grupo suman más del 100 %. |
| `mjml.unknown-social-network` | warning | Un nombre de `<mj-social-element>` sin icono integrado y sin `src`. |
| `mjml.script` | warning | `<script>` en el contenido. Los clientes de correo lo eliminan. |
| `mjml.missing-preview` | info | No hay `<mj-preview>`. |
| `mjml.missing-alt` | info | Un `<mj-image>` sin `alt`. |
| `mjml.button-without-link` | info | Un `<mj-button>` sin `href`. |

**Temple**

| Código | Gravedad | Significado |
| --- | --- | --- |
| `temple.unclosed-if` | error | `{{#if}}` sin `{{/if}}`. |
| `temple.endif-without-if` | error | `{{/if}}` sin `{{#if}}`. |
| `temple.else-without-if` | error | `{{else}}` fuera de un bloque. |
| `temple.duplicate-else` | error | Dos `{{else}}` en un mismo bloque. |
| `temple.unclosed-expression` | error | `{{` sin `}}`. |
| `temple.empty-expression` | error | `{{ }}`. |
| `temple.empty-condition` | error | `{{#if}}` sin variable. |
| `temple.malformed-else` | error | `{{else}}` escrito con espacios o argumentos. |
| `temple.unsupported-block` | error | Un bloque distinto de `{{#if}}`, como `{{#each}}`. |
| `temple.unsupported-syntax` | error | Llaves triples `{{{…}}}`, parciales `{{> …}}` o comentarios `{{! …}}`. |
| `temple.invalid-variable` | warning | Una variable que no es una ruta válida. |
| `temple.invalid-condition` | warning | Una condición que no es una ruta de variable. No se admiten comparaciones. |
| `temple.block-crosses-components` | warning | Un bloque que se abre en un componente y se cierra en otro. |

**Documento y compilador**

| Código | Gravedad | Significado |
| --- | --- | --- |
| `document.empty` | error | El origen está vacío. |
| `document.unrecognized` | error | No es marcado MJML, MJML JSON ni un documento MJML de Emailit. |
| `document.invalid-json` | error | El origen parece JSON, pero no se puede analizar. |
| `document.invalid-node` | error | MJML JSON con un nodo mal formado. |
| `document.too-large` | error | El origen ocupa más de 2 MB. |
| `document.unsupported-schema` | error | El `schema_version` del envoltorio es más reciente que el que lee Emailit. |
| `document.unsupported-mjml-version` | error | La versión de MJML del documento no se puede compilar. Consulta [Versiones y actualizaciones](#versions-and-upgrades). |
| `document.assumed-mjml-version` | info | El envoltorio no tiene `mjml_version`, así que se presupone la versión actual. |
| `document.mjml-upgraded` | info | Escrito para otra versión de MJML y compilado con la 5.4.1. |
| `compiler.failed` | error | MJML no ha podido renderizar el documento. |
| `compiler.gmail-clipping` | warning | El HTML ocupa más de 102 KB, así que Gmail lo recorta. |

## Temple en MJML

Las etiquetas de [Temple](/es/docs/templates/temple/) pasan sin cambios por la compilación de MJML. Emailit las renderiza para cada destinatario en el momento del envío, sobre el HTML compilado.

### Variables en el contenido y en los atributos

Las variables funcionan en el contenido y en cualquier atributo:

```xml
<mj-text>Hi {{first_name|"there"}},</mj-text>
<mj-button href="{{activation_url}}">Activate your account</mj-button>
<mj-image src="{{logo_url}}" alt="{{company|'Acme'}}" />
<mj-section background-color="{{brand_color|'#ffffff'}}">
```

- Dentro de un atributo, escribe los valores por defecto con comillas simples: `href="{{url|'https://example.com'}}"`.
- Los valores de atributo que contienen Temple no se comprueban por tipo, porque el valor solo se conoce en el momento del envío. Asegúrate de que la variable contiene un valor válido para el atributo, como un color para `background-color`.
- Los valores se insertan tal cual, sin escape HTML.

### Bloques condicionales

Dentro de un componente, pon el bloque en su contenido:

```xml
<mj-text>{{#if plan}}You are on the {{plan}} plan.{{else}}You are on the free plan.{{/if}}</mj-text>
```

Para mostrar u ocultar componentes enteros, pon las etiquetas del bloque en elementos `<mj-raw>` hermanos:

```xml
<mj-raw>{{#if vip}}</mj-raw>
<mj-section background-color="#fef3c7">
  <mj-column>
    <mj-text>Your VIP perks are ready.</mj-text>
  </mj-column>
</mj-section>
<mj-raw>{{/if}}</mj-raw>
```

Las etiquetas de bloque sueltas entre componentes se convierten en `<mj-raw>` al analizar el marcado, así que esto es lo mismo:

```xml
{{#if vip}}
<mj-section background-color="#fef3c7">
  …
</mj-section>
{{/if}}
```

MJML ignora cualquier otro texto entre componentes, que se notifica como `xml.stray-text`.

- Los bloques deben estar equilibrados en todo el documento. Una etiqueta sin cerrar o sobrante es un error.
- Abre y cierra cada bloque dentro del contenido de un mismo componente, o entre los `<mj-raw>` hermanos de un mismo padre. Un bloque que se abre en un componente y se cierra en otro recibe una advertencia `temple.block-crosses-components`, porque ocultarlo cortaría la estructura HTML.
- Los bloques se pueden anidar.

### Lo que no se admite

- `<mj-include>` se rechaza con `mjml.include-not-supported`. Pega el MJML incluido en el documento.
- Las etiquetas y los atributos que MJML 5.4.1 no define son errores.
- Temple no tiene bucles, helpers, parciales, comentarios, llaves triples ni comparaciones. Consulta [Temple](/es/docs/templates/temple/).

### Variables por canal

La misma plantilla MJML se puede enviar desde varios sitios, y cada uno aporta variables distintas:

| Enviada desde | Variables |
| --- | --- |
| [Enviar un email](/es/docs/api-reference/emails/send/) de la API con `template` | El objeto `variables` que pasas |
| Paso **Send email** de una automatización | Automatizaciones de contactos: los campos del contacto en el nivel superior (`{{first_name}}`, `{{email}}`), los campos personalizados como `{{cf.<key>}}` o `{{custom_fields.<key>}}`, además de `{{contact.*}}`, `{{payload.*}}` y `{{meta.*}}` |
| Campañas MJML | `{{first_name}}`, `{{last_name}}`, `{{email}}`, `{{unsubscribe_url}}`, `{{cf.<key>}}` y los mismos campos en `{{contact.*}}` |

Los editores insertan los campos personalizados como `{{cf.<key>}}`, que funciona en las campañas MJML y en las automatizaciones. En los envíos por API, pasa tú las variables.

Para previsualizar la versión de un destinatario, llama a [Renderizar MJML](/es/docs/api-reference/mjml/render/) con `variables`.

## Campañas

Una campaña con `content_type: "mjml"` guarda su MJML en `content`, en cualquiera de los [formatos de origen](#source-formats), y Emailit compila su `html`. Como en las plantillas, se ignora cualquier `html` que envíes. Un MJML no válido devuelve `422` con `errors.content` y `diagnostics`. Enviar un `content` vacío borra tanto el contenido como el HTML. Las respuestas de campañas incluyen el mismo objeto `mjml` que las de plantillas.

Las campañas MJML renderizan el asunto, el HTML y el texto con **Temple** para cada destinatario, también en los envíos de prueba. Están disponibles estas variables:

| Variable | Valor |
| --- | --- |
| `{{first_name}}` | Nombre del contacto |
| `{{last_name}}` | Apellidos del contacto |
| `{{email}}` | Dirección de email del contacto |
| `{{unsubscribe_url}}` | Enlace de baja de este contacto y esta campaña |
| `{{cf.<key>}}` | Campo personalizado del contacto, por ejemplo `{{cf.company}}` |
| `{{contact.first_name}}`, `{{contact.cf.<key>}}`, … | Los mismos campos en `contact` |

Los campos vacíos del contacto cuentan como ausentes, así que se aplican los valores por defecto: `{{first_name|"there"}}` se renderiza como `there` para un contacto sin nombre. Mantén un enlace `{{unsubscribe_url}}` en el pie de los emails de marketing.

Las campañas clásicas (HTML, texto y los demás editores) mantienen las etiquetas de combinación fijas:

| | Campañas clásicas | Campañas MJML |
| --- | --- | --- |
| Motor | Etiquetas de combinación fijas | Temple |
| `{{#if}}` … `{{else}}` … `{{/if}}` | No se procesa | Se admite |
| Valores por defecto como `{{first_name\|"there"}}` | No se procesan | Se admiten. Los campos vacíos cuentan como ausentes. |
| Mayúsculas y minúsculas | `{{FIRST_NAME}}` funciona | Las rutas distinguen entre mayúsculas y minúsculas |
| Etiquetas desconocidas | Se quedan en el mensaje tal como están escritas | Se renderizan vacías |

En el panel, crear una campaña a partir de una plantilla MJML copia el documento MJML de la plantilla en la campaña.

### Sin acceso a MJML

Durante la fase alfa, Emailit solo compila el MJML de las campañas para el equipo de Emailit. Para todos los demás, incluidas las claves de API, `content_type: "mjml"` sigue siendo la simple etiqueta que era antes de la fase alfa: `content` se guarda tal como lo envías, tú envías el HTML compilado en `html` y los envíos usan las etiquetas de combinación clásicas. Crear una campaña a partir de una plantilla MJML copia el HTML de la plantilla en una campaña HTML.

## Automatizaciones

El paso **Send email** hace referencia a una plantilla por su ID (`tem_…`). Las plantillas MJML funcionan como cualquier otra: el paso envía el HTML compilado de la plantilla y renderiza Temple con las variables de la automatización. Consulta [Emails de las automatizaciones](/es/docs/templates/temple/#automation-emails).

En la configuración del paso, **Design a new email** crea una plantilla MJML a partir de un diseño inicial, la selecciona para el paso y la abre en el Visual Editor. **Edit email** abre la plantilla MJML seleccionada. Los cambios modifican la propia plantilla, así que todos los pasos y las llamadas a la API que usan la plantilla los reciben. Sin acceso a MJML, el paso muestra en su lugar un enlace a la plantilla.

## Edición conjunta

Todas las personas que abren la misma plantilla o campaña MJML guardada editan un único borrador compartido en tiempo real, en cualquiera de los dos editores:

- **Presencia**: el encabezado muestra quién más está editando y qué está haciendo. En el Visual Editor ves sus selecciones, sus cursores y un breve resaltado de su color allí donde cambian algo. **Layers** muestra quién tiene seleccionado un componente. Selecciona el avatar de alguien para ir a su selección.
- **Los cambios se combinan**: los cambios en componentes, atributos o partes de un texto distintos se combinan en lugar de sobrescribirse. Mientras alguien escribe en un texto del lienzo, ese texto queda bloqueado para los demás.
- **Code Editor**: tus cambios se incorporan al borrador compartido mientras escribes. Los cambios de los demás aparecen en tu código cuando dejas de escribir, para que el cursor no salte. Si tu código tiene un error de sintaxis, esperan hasta que lo corrijas.
- **Deshacer y rehacer** solo deshacen tus propios cambios.
- **Guardar**: hay un único **Save** para todos. El encabezado muestra los cambios sin guardar de todo el borrador y quién guardó por última vez. Los envíos siempre usan la versión guardada.
- **El borrador se conserva**: cerrar el editor o perder la conexión no hace perder cambios. Se quedan en el borrador compartido y se sincronizan cuando vuelves a estar en línea. Al volver a abrir el editor se restauran los cambios sin guardar, y puedes descartarlos para volver a la versión guardada.
- **Guardado desde otro sitio**: cuando la plantilla o campaña se guarda fuera del editor (con la API, MCP o **Edit with AI**) mientras está abierta, un borrador que no tiene cambios sin guardar pasa a la versión guardada. Un borrador con cambios sin guardar los conserva y ofrece **Load saved version** o **Keep this draft**.
- **Eliminada**: si la plantilla o campaña se elimina, o deja de ser MJML, mientras editas, el editor te avisa y te permite copiar el MJML.

La edición conjunta requiere un MJML guardado y válido. Una plantilla o campaña cuyo MJML no se puede analizar, o que todavía no se ha guardado como MJML, se abre sin ella: cada persona edita por su cuenta y gana el último guardado. El editor lo indica en un aviso. En un espacio de trabajo suspendido, los editores son de solo lectura.

## Versiones y actualizaciones

Emailit compila con una sola versión de MJML a la vez, actualmente la 5.4.1. Cada documento guardado registra la `mjml_version` para la que está escrito, y Emailit la comprueba siempre que compila el documento:

| `mjml_version` del documento | Resultado |
| --- | --- |
| 5.4.1 | Se compila tal cual |
| Ausente | Se presupone la 5.4.1 (`document.assumed-mjml-version`, info) |
| Otra versión 5.x | Se compila con la 5.4.1 (`document.mjml-upgraded`, info) |
| 4.x | Se migra a MJML 5 y después se compila con la 5.4.1 (`document.mjml-upgraded`, info). MJML 4 y 5 comparten los mismos componentes y atributos; el HTML generado cambia ligeramente. |
| 3.x o anterior | Se rechaza con `document.unsupported-mjml-version` |
| Una versión principal más reciente | Se rechaza con `document.unsupported-mjml-version` |

Un documento cuyo `schema_version` es más reciente que el que lee Emailit se rechaza con `document.unsupported-schema`. Al guardar, el documento se guarda con la `mjml_version` y el `schema_version` actuales. Comprueba la vista previa después de una actualización.

Los editores muestran su versión y su registro de cambios. Cuando un documento se guardó con una versión del editor más reciente que la de la página que tienes abierta, el editor te pide que la recargues.

## MJML para agentes de IA

[Obtener la referencia de MJML](/es/docs/api-reference/mjml/reference/) da a las herramientas de desarrollo y a los modelos de IA lo que necesitan para escribir MJML válido para Emailit: cada componente con sus padres, hijos y atributos permitidos (tipo y valor por defecto), la guía de Temple, las reglas de escritura y un `reference_text` compacto en texto plano para los prompts.

En el [servidor MCP](/es/docs/mcp/), las sesiones del equipo de Emailit también reciben estas herramientas en el conjunto de herramientas `templates`:

| Herramienta | Descripción |
| --- | --- |
| `get-mjml-reference` | La referencia como texto: las versiones de MJML y de los editores, las reglas de escritura, la guía de Temple y la referencia de componentes. |
| `validate-mjml` | [Validar MJML](/es/docs/api-reference/mjml/validate/): `valid` y los diagnósticos. |
| `render-mjml` | [Renderizar MJML](/es/docs/api-reference/mjml/render/): el HTML compilado y, con `variables`, `rendered_html`. |
| `create-template`, `update-template` | También aceptan `editor: "mjml"` y `source`, el marcado MJML o el MJML JSON como cadena. Emailit compila el HTML. |
| `create-campaign`, `update-campaign` | También aceptan `content_type: "mjml"` con el MJML en `content`. |

Cuando un guardado no supera la validación, el error de la herramienta muestra los diagnósticos de error y de advertencia con sus números de línea, para que el agente pueda corregir el origen. Un flujo típico: leer la referencia, escribir el MJML, llamar a `validate-mjml` hasta que `valid` sea `true`, guardar con `create-template` y después comprobar la versión de un destinatario con `render-mjml`. Las demás sesiones no ven estas herramientas ni estos parámetros.

## En el panel

- **Plantillas**: crea una plantilla y elige **MJML Visual Editor (Alpha)** o **MJML Code Editor (Alpha)**.
- **Visual Editor**: arrastrar y soltar sobre el email renderizado, un árbol de capas, un panel de propiedades para cada atributo de MJML, la configuración del documento (head, fuentes, estilos y atributos por defecto), variables de Temple en cualquier propiedad y bloques condicionales alrededor de los componentes.
- **Code Editor**: autocompletado de etiquetas, atributos y valores de MJML y de Temple, validación en línea con correcciones rápidas, y formateo.
- **Ambos editores**: una vista previa en directo para escritorio y móvil compilada en el navegador con MJML 5.4.1, una vista previa con datos de ejemplo (con Temple renderizado), una lista de problemas y un asistente de IA cuando está activado. Puedes cambiar entre Visual y Code en el mismo documento; para pasar a Visual, el código no debe tener errores de sintaxis. No se puede guardar mientras el MJML tenga errores.
- **Edición conjunta**: los compañeros que abren la misma plantilla o campaña la editan en tiempo real. Consulta [Edición conjunta](#editing-together).
- **Edit with AI**: describe un cambio en una plantilla o campaña MJML sin abrir el editor.
- **Importar**: un archivo `.mjml`, un archivo `.json` de MJML JSON o de documento MJML de Emailit, o un ZIP con `template.mjml` y una carpeta `images/` en la raíz.
- **Exportar**: MJML (marcado), MJML JSON (el documento guardado), HTML o un ZIP con `template.mjml`, `template.html` y `images/`. La exportación funciona para todos.
- **Campañas**: elige el MJML Visual Editor o el MJML Code Editor para el contenido de la campaña.
- **Automatizaciones**: diseña el email de un paso **Send email** sin salir de él. Consulta [Automatizaciones](#automations).

## Ver también

- [Crear y editar plantillas](/es/docs/templates/editors/)
- [Lenguaje de plantillas Temple](/es/docs/templates/temple/)
- [Referencia de la API de MJML](/es/docs/api-reference/mjml/)
- [Importar y exportar](/es/docs/templates/import-export/)

---
Fuente: https://emailit.com/es/docs/templates/mjml/
