Skip to main content
LMX (Loops Markup Language) is an XML-based format for writing email content in Loops. Every piece of content is represented by an explicit PascalCase tag. LMX can be used with the Content API to create and update campaign and transactional email messages programmatically. LMX sits between the API and our editor, making it possible to edit emails across both the editor and API. You can keep LMX in your codebase and update draft email messages through the Content API or email messages CLI. Fetch the current contentRevisionId, edit the LMX in Git, and send the update back with revision protection.

Campaign content examples

Create campaigns, query themes and components, and update email messages with LMX.

Update email message API

Send serialized LMX through the Content API for campaign and transactional email messages.

Create campaign API

Create a draft campaign and email message before adding LMX content.

Loops CLI

Use the CLI for local setup, authentication, and Content API workflows.

Themes API

Find theme IDs and style attributes for the LMX <Style /> tag.

Components API

Find reusable components for the LMX <Component /> tag.

LMX examples

Here are some examples of how to use LMX tags to create emails.
A list
Two-column layout
Full campaign example
Transactional email example

Core rules

  • LMX is XML, not HTML or Markdown. Tags are case-sensitive (for example, <Paragraph>, not <paragraph>).
  • LMX is not MJML. Do not use MJML tags (such as <mj-text>).
  • Do not use the editor’s dynamic tag syntax in LMX documents (for example {DATA_VARIABLE:resetLink} or unprefixed {firstName}). Use {contact.X} for campaign contact properties and {data.X} for transactional email data variables.
  • A document is a sequence of top-level block tags, optionally with one top-level <Style />.
  • Text is not allowed at the top level. Wrap top-level text in a block tag like <Paragraph>.
  • Top-level inline tags and variables are invalid.
  • Required attributes must be present (for example, <Image /> requires src).
  • Self-closing tags must end with /> (for example, <Image ... />, <Br />).
  • Unknown tags are rejected. Use only documented attributes in public LMX examples.
  • Attribute values are quoted strings. Numbers and booleans are passed as strings.
  • Whitespace in text content collapses like HTML, except inside <CodeBlock>, where interior whitespace is preserved. Use <Br /> for explicit line breaks.
  • Whitespace between block tags is ignored, so pretty-printing is safe.
  • Escape text and attributes as needed (&lt;, &amp;, &quot;).
Emails automatically have a footer appended, so you don’t need to include your address or unsubscribe link at the bottom of your LMX content.

Tags

Top-level tags define the structure of an email. Child-only structural tags are valid only inside their parent tags.

Tag reference

Document styles

Use the optional top-level <Style /> tag to style the email. Use this to apply a theme to your email and add custom styles, just like you would in the Style panel in the editor. Use a combination of themeId and other attributes to bring in defaults while also overriding specific styles. You can also style individual elements in your email using tag attributes (for example, <Button bgColor="#000000">Open account</Button> overrides <Style buttonBodyColor="#CCCCCC" /> for that button). Styles applied in <Style /> will apply to all content in the email. For example, defining buttonBodyColor in the <Style /> tag will apply to all buttons in the email. Self-closing tag. At most one per document.

Headings

Use <H1>, <H2>, and <H3> for headings.

Paragraphs

Use <Paragraph> for paragraph text.

Quotes

Use <Quote> for blockquote content.

Code blocks

Use <CodeBlock> for code blocks. Note: inline tags and variable parsing are disabled inside code blocks.

Buttons

Use <Button> for buttons. Button content may contain plain text and dynamic content variables such as {contact.firstName} or {data.firstName}. Inline formatting tags are not allowed inside buttons.

Images

Use <Image /> for images. src must be a Loops-hosted image. Upload images using the Uploads API endpoints and use the returned URL as src. For an externally hosted dynamic image, see Dynamic images below.

Dynamic or externally hosted images

If you want a per-recipient image URL, set dynamicSrc to a URL containing a variable (for example, {contact.avatarUrl} or {data.avatarUrl}). The image URL should come from a contact property or data variable. You must also set src to a Loops-hosted static placeholder (this image renders in the Loops editor). When the email is generated for each recipient, the resolved dynamicSrc value is injected as the image src. For images hosted on an external host, set src to a Loops-hosted static placeholder, then set dynamicSrc to the external image URL. Dynamic image URLs must be publicly accessible and use an email-safe image extension like .jpg or .png. More about dynamic images.

Dividers

Use <Divider /> for divider lines. Self-closing tag.

Line breaks

Use <Br /> for line breaks in inline contexts. It is not valid at the top level. Self-closing tag.

Lists

Use <OrderedList> or <UnorderedList> with <ListItem> children only. These tags must contain at least one <ListItem>.

List items

Use <ListItem> for list items. Only valid inside <OrderedList> and <UnorderedList> tags. Can only contain inline content.

Columns

Use <Columns> for columns. Must contain between two and four <ColumnItem> children. No other tags are allowed. Nested <Columns> tags are not supported.
Use <ColumnItem> for column content containers. Only valid inside a <Columns> tag. No attributes.

Components

Use <Component> to add a component. Can be self-closing, or can contain block elements, which will override the component’s default content. Children are block tags. Nested <Component> tags are not supported.

Sections

Use <Section> to group related block content in a shared clickable or styled container. Children are block tags. Nested <Section> tags are not supported.

Icons

Use <Icons> for lists of icons. Children must be <Icon /> with no other tags allowed. At least one <Icon /> child is required (maximum 100).
Use <Icon /> for individual icons. Self-closing tag. Only valid inside an <Icons> tag.

Inline tags

Inline tags format text content inside block elements. Inline tags are valid only inside inline-content blocks such as <Paragraph>, headings, <Quote>, and <ListItem>.

Inline tag attributes

Dynamic content

You can add dynamic content like contact properties by using a tag syntax with a prefix, for example {contact.firstName}. Dynamic tags can be added to email message lmx bodies and also in other fields like subject, previewText, fromName, fromEmail and replyToEmail. LMX campaign content uses contact properties and the public unsubscribe URL. Transactional email content uses data variables.
Unprefixed placeholders like {firstName} or {resetLink} are not valid in LMX. Neither are other Loops variable prefixes used in MJML or the editor, including {EVENT_PROPERTY:...} for event properties in workflow emails and {DATA_VARIABLE:...} for data variables in transactional emails.These placeholders are still valid in MJML emails and in the Loops editor. In the future, all variables will require a prefix.

Contact properties

Use {contact.<apiName>} for campaign personalization, for example {contact.firstName}. Default contact properties include firstName, lastName, email, notes, source, userGroup, userId, subscribed, and createdAt.

Data variables

Use {data.<variableName>} in transactional email LMX. The name after data. must match a key in the dataVariables object when sending the email.
LMX content
Send transactional email payload
Transactional data variable rules:
  • Names are case-sensitive. {data.resetLink} and {data.ResetLink} are different variables.
  • Names may contain only letters, numbers, underscores, and dashes.
  • API values may be string or number.
  • Non-optional variables must be present in dataVariables or the send fails.
  • Optional variables may be omitted from the request or sent as an empty string "" (null does not work). Mark a data variable as optional in the Loops editor.

Where variables are allowed

Variables are allowed in:
  • Inline content (headings, paragraphs, quotes, list items, and inline tags)
  • Button text
  • Supported dynamic attributes: Button href, Link href, Image alt, Image href, Image dynamicSrc, and Section href
Variables are not allowed:
  • At the top level
  • Inside <CodeBlock> (braces are literal text)
  • In unsupported attributes such as Image src

Variables in attributes

Only these attribute values may include variables:
  • Button href
  • Image alt, href, and dynamicSrc
  • Link href
  • Section href
Image src must be a Loops-hosted static URL with no variables. User-hosted URLs are not supported in src. Putting a variable like {contact.avatarUrl} in src is not supported and validation returns unsupported_dynamic_attr. When the image URL should vary per recipient (including externally hosted URLs), set dynamicSrc to a variable such as {contact.avatarUrl} or {data.avatarUrl} and keep src as a Loops-hosted placeholder; at send time, the resolved dynamicSrc value replaces src.

Fallback values

LMX does not support inline fallback syntax in variable references. These forms are not valid in LMX: {contact.firstName|there}, {contact.firstName:there}, {contact.firstName ?? "there"}, and fallback="there" on variable attributes. Use plain variable references in LMX (for example, {contact.firstName} or {data.firstName}). For contact properties, configure fallback values through the Loops editor. For transactional emails, mark a data variable as optional in the editor instead of inventing inline fallback syntax.

Nesting rules

LMX validates structure, not just syntax. A few key rules:
  • Root-level content must use supported top-level block tags (H1, H2, H3, Paragraph, Quote, CodeBlock, Button, Image, Divider, OrderedList, UnorderedList, Columns, Component, Section, Icons, Style).
  • Inline tags cannot appear at the top level.
  • <ListItem> and <Quote> only accept inline content.
  • <Columns> can only contain <ColumnItem> tags.
  • <ColumnItem> can contain block content, but not nested <Columns> or other <ColumnItem> tags.
  • <Style /> is metadata and is only allowed at the top level.
If a tag, attribute, or nesting pattern is invalid, validation issues are returned so problems can be fixed before sending.
Last modified on July 2, 2026