Convert MJML markup into AMP for Email compatible HTML.
Build AMP-compliant responsive emails using MJML's semantic syntax.
- Built on the mature MJML template engine with clean, intuitive syntax
- Outputs AMP for Email compliant HTML
- Automatic
<amp-img>conversion and AMP component handling - Image URL extraction utility for batch dimension fetching
- Works in Node.js and browser environments
- TypeScript type definitions included
Try it online: https://mjml2amp.easyemail.pro/
npm install mjml2ampAMP requires <amp-img> to have explicit width and height. The conversion follows three steps: extract image URLs → fetch image dimensions → convert with dimensions.
import { mjml2amp, getImageUrlsForAmp } from 'mjml2amp'
import probe from 'probe-image-size' // or any image dimension library
const mjmlString = `
<mjml>
<mj-body>
<mj-section>
<mj-column>
<mj-image src="https://example.com/hero.jpg" width="600px" />
<mj-text>Hello AMP Email!</mj-text>
</mj-column>
</mj-section>
</mj-body>
</mjml>
`
// 1. Extract image URLs that need dimensions
const urls = await getImageUrlsForAmp(mjmlString)
// => ['https://example.com/hero.jpg']
// 2. Fetch actual image dimensions
const imageDimensions = {}
await Promise.all(
urls.map(async (url) => {
const { width, height } = await probe(url)
imageDimensions[url] = { width, height }
})
)
// 3. Convert with dimensions
const result = mjml2amp(mjmlString, { imageDimensions })
console.log(result.html) // AMP HTML output
console.log(result.errors) // MJML parse errors, if anyIf the template has no images, or all images already have explicit heights via the mj-image height attribute, you can skip the dimension step:
const result = mjml2amp(mjmlString, { skipImageDimensions: true })Converts an MJML string to AMP HTML.
Parameters:
| Parameter | Type | Description |
|---|---|---|
input |
string |
MJML template string |
options |
MJMLOptions |
Optional configuration |
Options:
| Option | Type | Default | Description |
|---|---|---|---|
keepComments |
boolean |
true |
Preserve HTML comments in output |
ignoreIncludes |
boolean |
true |
Ignore mj-include tags |
validationLevel |
string |
'soft' |
Validation level: 'strict', 'soft', or 'skip' |
filePath |
string |
'.' |
File path for resolving relative mj-include paths |
imageDimensions |
object |
— | Map of image URL to { width, height } |
skipImageDimensions |
boolean |
false |
Skip image dimension processing |
imageDimensionsStrict |
boolean |
true |
Throw on missing dimensions; set to false to warn only |
preprocessors |
function[] |
[] |
XML preprocessor functions |
Returns:
interface MJMLParseResults {
html: string // Generated AMP HTML
json?: MJMLJsonObject // Parsed JSON structure
errors: MJMLParseError[] // Parse error list
}Extracts image URLs from AMP output that require explicit dimensions.
Parameters: Same as mjml2amp
Returns: Promise<string[]> — Array of image URLs
mjml2amp supports the following MJML core components and converts them to AMP-compatible HTML:
| Component | Description |
|---|---|
mj-body |
Email body |
mj-section |
Content section |
mj-column |
Column layout |
mj-text |
Text content |
mj-image |
Image (converted to <amp-img>) |
mj-button |
Button |
mj-divider |
Divider |
mj-spacer |
Spacer |
mj-table |
Table |
mj-social |
Social icons |
mj-hero |
Full-width hero section |
mj-navbar |
Navigation bar |
mj-accordion |
Accordion |
mj-carousel |
Carousel |
mj-group |
Column group |
mj-wrapper |
Full-width wrapper |
mj-raw |
Raw HTML |
mj-head |
Head configuration |
This project is licensed under the Business Source License 1.1 (BSL-1.1). See LICENSE.md for details.