listmonk icon indicating copy to clipboard operation
listmonk copied to clipboard

Add native MJML support

Open preslavrachev opened this issue 5 months ago • 12 comments

Hi 👋,

First of all, thanks for maintaining listmonk — it’s an awesome project!

I’d like to introduce a Go library I’ve been working on: gomjml. It provides a Go wrapper around MJML, the popular framework for responsive email markup. The goal is to make it easy to define MJML templates directly in Go projects and render them into production-ready HTML.

Why this might be useful for listmonk

  • Responsive HTML emails: MJML is a widely used standard for email templating, ensuring compatibility across major clients.
  • Native Go integration: gomjml makes it possible to render MJML templates in Go code without external build steps or calling external APIS.
  • Potential use cases in listmonk:
    • As an alternative templating engine for users who prefer MJML.
    • To simplify building responsive email templates directly within the app.
    • To provide a ready-made solution for users struggling with HTML email quirks.

Links

  • GitHub repo: https://github.com/preslavrachev/gomjml
  • MJML project: https://mjml.io/

I’d love to hear your thoughts on whether this could be integrated (either natively or as an optional plugin/extension) to enhance listmonk’s email templating options.

preslavrachev avatar Aug 16 '25 17:08 preslavrachev

Nice, @preslavrachev. MJML has been requested a few times here before. I'll give native integration a shot.

knadh avatar Aug 18 '25 13:08 knadh

Hi @preslavrachev , I just launched an open-source alternative with a visual drag'n drop MJML editor at https://github.com/Notifuse/notifuse, feel free to try it out!

pierre-b avatar Aug 26 '25 08:08 pierre-b

Hi @pierre-b - nice to see you've decided to use Go for the backend! I can see you are currently using the WASM-bindings version of the MJML compiler that calls into the official JS library.

I am wondering if you'd be interested in trying out the native version I have made open-source recently, and compare the performance. One of my concerns with the WASM one was that it won't scale well under load. With the native one, you should barely see any significant changes.

I would be happy to support you in porting that.

preslavrachev avatar Aug 27 '25 08:08 preslavrachev

Amazing news @preslavrachev ! I was thinking of doing the same but never found time... it was definitely needed in the go ecosystem! Will ping you when the integration is done.

pierre-b avatar Aug 27 '25 08:08 pierre-b

@pierre-b - fantastic, happy to hear! Yeah, it's a major endeavor. I mainly did it, because our team has all sorts of Go projects that would greatly benefit from not having to call an external API, or precompile and store unreadable HTML files in source control. And, I must admit, the AI helped here a ton. I wouldn't have achieved that in 10x the amount of time, if I had to code by hand. Claude Code required a bunch of course correction on my side as well, but having established a solid testing base, I could just let it solve the implementation by more or less following TDD.

Anyway, I'd be happy to support you, and update the library thanks to your feedback. It should go without saying that we are far from v1.0, so API and implementation might still change, but for the most part, existing templates should work fine. You are more than welcome to prove me wrong - if you have an edge case that's not rendering as it should, we can always add it to the suite of integration tests.

preslavrachev avatar Aug 27 '25 08:08 preslavrachev

Yes TDD is the key to success with Claude, especially if the test suite already existed in the Rust codebase :) I'll follow up in your repo issues!

pierre-b avatar Aug 27 '25 08:08 pierre-b

@preslavrachev I actually gave this a shot two weeks ago https://github.com/knadh/listmonk/pull/2643/files but mjml.Render() was failing despite being given valid markup. I haven't had a chance to debug it further, but please feel free to try out the branch if you're able to.

knadh avatar Aug 31 '25 07:08 knadh

@knadh - indeed, @pierre-b and I discovered some breaking bugs, and a fix is on the way. Can you send me the exact MJML content you tested with?

If you want to try and see if this works, the beta tag is v0.7.0-beta.2 - I will soon make a proper v0.7.0 release.

preslavrachev avatar Aug 31 '25 11:08 preslavrachev

@knadh https://github.com/preslavrachev/gomjml/releases/tag/v0.7.0 is out with some of the critical fixes. Try it out by forcing go mod to update to latest.

preslavrachev avatar Sep 01 '25 13:09 preslavrachev

Seems to be working fine now @preslavrachev. I've updated https://github.com/knadh/listmonk/pull/2643 to also ship with a default MJML template.

Please try it out. You can compile from source or use the attached bin: listmonk-v5.2.0-rc1.tar.gz

knadh avatar Oct 25 '25 11:10 knadh

@knadh Great to hear 🙌 — indeed, v0.10.0 was a major milestone in achieving feature-parity with MJML. I was previously misled to think that going after MRML (MJML's Rust compiler) was a better idea, because language-wise, Go and Rust are closer to one another. Big mistake!

Nonetheless, the library is finally on the right track, and I'd be happy to see it make listmonk users' lives easier.

I would have to build a Mac-compatible, version of the branch to test it, but if you happen to merge to master in the menatime, let me know. I'd be happy to spread the news.

preslavrachev avatar Oct 25 '25 15:10 preslavrachev

when are you merging ?

manutheblacker avatar Nov 05 '25 18:11 manutheblacker