MJML
Reach for this subpackage when you want to compile a mail body from MJML rather than plain HTML or html/template.
import "github.com/gp-system/mail/mjml"
mail/mjml compiles MJML markup into responsive, email-client-friendly HTML, and is itself a mail.Body: it slots into Message.WithBody exactly like a plain text or HTML body. The source is first rendered as an html/template (interpolated data is escaped), then compiled from MJML. It runs in pure Go (Boostport/mjml-go, wazero WASM runtime). No Node.js needed for build or runtime.
Template and String
body := mjml.Template(tmpls, "templates/order_confirmation.mjml.tmpl", data).
WithTextTemplate("templates/order_confirmation.txt.tmpl")
// or from an inline source:
body := mjml.String(`<mjml><mj-body>...</mj-body></mjml>`, data)
mjml.Template reads from an fs.FS (typically a //go:embed directory), the same signature mail.Template uses; mjml.String compiles an inline source string. Both can be extended with WithFuncs(template.FuncMap) before parsing, and WithTextTemplate attaches the plain-text alternative (there is no automatic text derivation, see Body types).
Worked example
A minimal order-confirmation template (templates/order_confirmation.mjml.tmpl):
<mjml>
<mj-body>
<mj-section>
<mj-column>
<mj-text font-size="20px" color="#333333">Hi {{.CustomerName}},</mj-text>
<mj-text>Your order (#{{.OrderID}}) has arrived and is on its way soon.</mj-text>
<mj-button href="{{.OrderURL}}" background-color="#2563eb">View your order</mj-button>
</mj-column>
</mj-section>
</mj-body>
</mjml>
Calling mjml.Template(tmpls, "templates/order_confirmation.mjml.tmpl", data) first renders this file as an html/template: {{.CustomerName}}, {{.OrderID}}, and {{.OrderURL}} are filled in from data, escaped. Boostport/mjml-go then compiles the resulting MJML: <mj-section>/<mj-column> become a fixed-width, table-based layout, <mj-button> becomes a button with a VML fallback that renders correctly in Outlook, and <mj-text> becomes a paragraph with sane font size and line height, all without a single hand-written media query or layout table. The result, wrapped as a mail.Body, slots into Message.WithBody exactly like a plain HTML body (see the Overview for the full call chain).
Options
mjml.Minify(bool): minify the compiled HTML; defaulttrue.mjml.ValidationLevel("strict" | "soft" | "skip"): MJML validation strictness; defaultsoft.
The WASM cost
mail/mjml links a WASM runtime into the binary, and the first render pays for loading the WASM module. Subsequent calls are cheaper. Only the binary that actually imports the package carries that cost: the mail root and the smtp driver know nothing about mjml. Typically only cmd/worker imports it.With the kit
The shop sample app's sendOrderConfirmation listener renders an order confirmation this way; see the worked example on the overview page. Generating a module-level notifier around a template like this is what add mail is for; see its reference for the exact generated shape.