A self-hosted alternative to the mjml API. Built with express.
The API is compatible with https://mjml.io/api in that it exposes only a single endpoint: /v1/render.
Unlike the official API, authentication is optional and can be configured via parameters. It is recommended to run this server within your private network.
Jump to:
You're writing an app in another language than Javascript and need to interop with MJML. Instead of embedding NodeJS in your Python image you can call MJML compilation over HTTP.
You can alternatively use the MJML API, but it's currently invite only and has privacy implications (do you want your emails to be sent to yet another third party?).
For an elaborate discussion see: mjmlio/mjml#340
These options can be set globally via CLI or per-request via JSON:
| Option (POST) | CLI Flag | ENV Var | Default | Description |
|---|---|---|---|---|
keepComments |
--keep-comments |
MJML_KEEP_COMMENTS |
true | Keep MJML comments in the HTML output |
beautify |
--beautify |
MJML_BEAUTIFY |
false | Pretty print the output HTML |
minify |
--minify |
MJML_MINIFY |
false | Minify the resulting HTML |
validationLevel |
--validation-level |
MJML_VALIDATION_LEVEL |
soft | MJML validation: strict, soft, or skip |
--host |
MJML_HOST |
0.0.0.0 | Host to bind the server | |
--port |
MJML_PORT |
15500 | Port to run the server on | |
--max-body |
MJML_MAX_BODY |
1mb | Maximum HTTP request body size | |
--use-compression |
MJML_USE_COMPRESSION |
true | Gzip compress HTTP responses | |
--auth-user |
MJML_AUTH_USER |
HTTP Basic Auth username (requires auth-pass) |
||
--auth-pass |
MJML_AUTH_PASS |
HTTP Basic Auth password (requires auth-user) |
To run the MJML server using Docker, you can use the following command:
docker run -p 15500:15500 mactorient/mjml-server:latestYou can then use the following command to render MJML to HTML:
$ curl -i -X POST http://localhost:15500/v1/render \
-H "Content-Type: application/json" \
-d '{"mjml": "<mjml><mj-body><mj-section><mj-column><mj-text>Hello world</mj-text></mj-column></mj-section></mj-body></mjml>"}'
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Content-Length: 4272
ETag: ...
Vary: Accept-Encoding
Date: Tue, 17 Jun 2025 18:55:22 GMT
Connection: keep-alive
Keep-Alive: timeout=5
{
"html": "<!doctype html>\n<html ...</html>",
"mjml": "<mjml>...</mjml>",
"mjml_version": "^4.15.3",
"errors": [],
}You can run the server using Docker with the following command:
docker run -d -p 15500:15500 mactorient/mjml-server:latestFor docker compose, you can use the following docker-compose.yml:
services:
mjml-server:
image: mactorient/mjml-server:latest
expose:
- '15500'
environment:
MJML_MINIFY: 'true'
MJML_KEEP_COMMENTS: 'false'
MJML_AUTH_USER: 'mjml'
MJML_AUTH_PASS: 'password'
MJML_VALIDATION_LEVEL: 'strict'To run the MJML server in development mode, you can clone the repository and run it using Bun:
$ git clone https://github.com/mertemr/mjml-server.git$ cd mjml-server$ bun install$ bun start -h
Usage: index.js [options]
Server Options
--host Server host [env: MJML_HOST] [string] [default: "0.0.0.0"]
--port Server port [env: MJML_PORT] [number] [default: 15500]
--use-compression Use compression for responses [env: MJML_USE_COMPRESSION] [boolean] [default: true]
Output Options
--keep-comments Keep comments in the HTML output [env: MJML_KEEP_COMMENTS] [boolean] [default: true]
--beautify Beautify the HTML output [env: MJML_BEAUTIFY] [boolean] [default: false]
--minify Minify the HTML output [env: MJML_MINIFY] [boolean] [default: false]
--validation-level Available values for the validator [env: MJML_VALIDATION_LEVEL] [string] [choices: "strict", "soft", "skip"] [default: "soft"]
--max-body Max size of the http body [env: MJML_MAX_BODY] [string] [default: "1mb"]
Authentication Options
--auth-user Username for HTTP Basic Authentication [env: MJML_AUTH_USER] [string]
--auth-pass Password for HTTP Basic Authentication [env: MJML_AUTH_PASS] [string]
Options:
-h, --help Show help [boolean]
-v, --version Show version number [boolean]
Examples:
index.js --port 3000 Start the server on port 3000.
index.js --minify --no-keep-comments Minify the output and do not keep comments.
index.js --auth-user admin --auth-pass 1234 Use HTTP basic auth.
For more information, visit https://github.com/mertemr/mjml-serverContributions are welcome! Feel free to open issues or submit pull requests for any improvements or features you would like to see.
This project originates from eatclub/mjml-server, which itself is a fork of the original mertemr/mjml-server by Dani Hodovic.
This fork has been significantly modernized and improved to better suit our needs, including:
-
A modernized Docker build with significantly reduced CVE exposure
-
Security-first defaults in HTTP and container configuration
-
Improved logging, monitoring, and error handling
-
Enhanced configuration management for scalability and maintainability
This project is licensed under the MIT License. See the LICENSE file for details