mjmlio/mjml · warning

[MJML] mj-include tags were found but includes are disabled…

Error message

[MJML] mj-include tags were found but includes are disabled by default.\n  Files: ${filesWithIgnoredIncludes.join(', ')}\n  To enable includes, add --config.allowIncludes true to your command.\n  See https://documentation.mjml.io/#mj-include for security notes.

What it means

By default MJML disables mj-include processing for security reasons. When the CLI detects <mj-include> tags in the source input but includes were not enabled, it warns that those tags were ignored (left unprocessed) and output will not contain the included content.

Solutions

  1. Add --config.allowIncludes true to the mjml command to enable includes
  2. Then configure --config.includePath with the directories that may be included (see the related denied-includes warning)
  3. Or remove/replace the <mj-include> tags if includes are not wanted
  4. Pin/lock team build scripts so the flag is not lost when commands are copied

Example fix

// before
mjml email.mjml
// after
mjml email.mjml --config.allowIncludes true --config.includePath ./partials
Defensive patterns

Strategy: validation

Validate before calling

const src = fs.readFileSync(input, 'utf8')
if (/<mj-include\b/i.test(src) && !allowIncludes) {
  throw new Error('Input uses <mj-include>; run with --config.allowIncludes true')
}

Type guard

const usesIncludes = (mjml) => typeof mjml === 'string' && /<mj-include\b/i.test(mjml)

Prevention

When it happens

Trigger: Running the mjml CLI on a file whose source matches /<mj-include\b/i without passing --config.allowIncludes true. No includePath check even runs; the includes are simply skipped.

Common situations: Upgrading MJML from a version where includes were on by default; copying templates that use mj-include into a build that never opted in; new team members unaware of the allowIncludes flag.

Related errors


AI-assisted analysis of mjmlio/mjml@6c01d35af5 (2026-09-02). Data as JSON: /api/errors/9c1f51ddad4e3b45. Report an issue: GitHub.

Appendix: source

Thrown at packages/mjml-cli/src/client.js:350

      // eslint-disable-next-line no-console
      console.warn(
        `[MJML] Some mj-include paths were denied because they are outside the allowed directories.\n` +
          `  Files: ${filesWithDeniedIncludes.join(', ')}\n` +
          `  Add the include directories to --config.includePath to allow them.\n` +
          `  See https://documentation.mjml.io/#mj-include for security notes.`,
      )
    }
  }

  // Warn when mj-include tags are present but includes are still ignored.
  if (config.ignoreIncludes !== false) {
    const MJ_INCLUDE_RE = /<mj-include\b/i
    const filesWithIgnoredIncludes = inputs
      .filter((i) => i && i.mjml && MJ_INCLUDE_RE.test(i.mjml))
      .map((i) => i.file)
    if (filesWithIgnoredIncludes.length) {
      // eslint-disable-next-line no-console
      console.warn(
        `[MJML] mj-include tags were found but includes are disabled by default.\n` +
          `  Files: ${filesWithIgnoredIncludes.join(', ')}\n` +
          `  To enable includes, add --config.allowIncludes true to your command.\n` +
          `  See https://documentation.mjml.io/#mj-include for security notes.`,
      )
    }
  }

  failedStream.forEach(({ error, file }) => {
    console.error(`${file ? `File: ${file}\n` : null}${error}`) // eslint-disable-line no-console

    if (config.stack) {
      console.error(error.stack) // eslint-disable-line no-console
    }
  })

  if (inputOpt === 'v') {
    const isInvalid =

View on GitHub (pinned to 6c01d35af5)