Built-in mail preview UI for dev mode

Hi everyone,
I’ve been working on something and wanted to share it with you before opening a PR :smile: a dev-mode mail preview UI for Meteor :partying_face:

Concept

This adds a simple web UI at /__meteor_mail__ that captures every outgoing email and lets you browse them in your browser with rendered HTML, plain text, HTML source, all the metadata. Zero config, no third-party service, completely absent in production. And of course, emails are still printed to the console, so this is purely additive, it doesn’t change any existing behavior :smile:

In other frameworks

  • Ruby on Rails has had Action Mailer Previews built-in since 4.1 (2014!). Available at /rails/mailers/, zero setup
  • Phoenix/Elixir — Swoosh ships with a local adapter and a built-in mailbox viewer. Part of the default Phoenix stack, works out of the box
  • Laravel lets you render Mailables directly in browser routes, and since v9+ has first-party preview support. The ecosystem also has great tools like Mailpit baked in
  • Django ships a console email backend out of the box; the community fills the visual gap with django-debug-toolbar’s mail panel

Where should it live?

That’s the question I’d genuinely love your input on :grimacing:

Inside the email package:

  • Zero friction — works out of the box, no extra package to add
  • Direct access to Email.hookSend, clean integration
  • What Rails and Phoenix do: preview is part of the mailer itself
  • Minimal footprint (~200 lines, dev-mode only, webapp as a weak dep)

As a separate email-preview package:

  • Keeps the email package focused purely on sending
  • Gives developers the choice

I have a working prototype in both cases, so I’m really open to either direction so what do you think would fit best with the project’s philosophy?




Would love to hear your thoughts! :slightly_smiling_face:

5 Likes

I love this idea. Would be extremely useful for my dev workflow.

Edit: I think it is also time to modernize the default email templates. But that would be separate from this.

You could make a tiny package and if it all aligns, maybe integrated into the core? @italojs @nachocodoner

Also if I’m not mistaken @fredmaiaarantes has some resend package which is nice to have nowadays

I love it, had built something similar for myself before, but having it on a separate route makes even more sense.

Does it only run in development mode? It would be cool if it could live on the server too, with being able to write a simple function that defines user access permissions.

We need to see what the Meteor team says and how we implement it, but to me, for security reasons — or even performance reasons — implementing it live might not be a good idea. It currently lives in the cache, and I set a limit of 10 for my example so Idk :thinking:

Maybe something like

EmailPreview.config({
  enabledInDevelop: true, // allow in dev
  enabledInProduction: true, // allow in prod
  authorize: (userId) => Roles.userIsInRole(userId, 'admin')
});

But let’s see what the meteor team wants then we can properly do that :smile:

I also have this built into https://todo-sample.meteorapp.com/ and mentioned here that this would be a great addition to meteor!

If you try to login with email, it will say to check the dev mail and you’ll be able to see the messages in real time. You can test with a fake email.

ScreenFlow

3 Likes

npm i @dupontbertrand/meteor-dev-mail --save-dev

1 Like

Yes, it was quite outdated, and I worked on updating it last week. I just need to test it a bit more.

2 Likes

Why not use Mailpit? Works perfectly for me, easy to setup (install and enter the URL, è voila!)

Mailpit looks great, but seems to be for a little bit different use case.

1 Like

Make it a choice, not everybody wants to use it.

Thanks, you’re on a roll, Bertrand.

2 Likes

Who said that in these modern times AI was going to kill creativity?!

Because, I just see projects, tools, and ecosystems getting fresh air in their implementations and contributors strongly motivated. This is great!

I love what you developed here, and honestly, the other ideas you pushed directly into the core.

This is my personal take, but I’d like this idea to first take shape as a community package. Why?

It can continue the experimentation phase without friction or blockers in the core. Releases in a community package context are faster. Betas, changes, features, and bug fixes can definitely happen without taking much extra time. It allows the idea to be containerized, opt-in and ready to use by anybody in the community, with rapid feedback on everything.

After all that can be seen in this thread about its development and execution, we can then ensure we move the changes into the core if it feels like a win for the DX of working with emails (I can already see strong benefits :grin:). Then we can have proper future versions in 3.x including these changes as beta to consolidate them and finally an official release.

3 Likes

wow this is very good!

I very much agree with what @nachocodoner has replied here, and maybe(and if @dupontbertrand is down for it) we could have a section in Community Packages | Docs for this package. What do you think?

There, we can have a link to an example repo, etc

I like the idea of the old Meteor days to have something like this out of the box with the option to remove/replace it when not needed.

1 Like

Here you go! The package is available here and the GitHub repo!

Feel free to try it out and let me know your feedback :slight_smile:

1 Like

Thanks @grubba, I’d love that! I’m definitely down for having it listed in the Community Packages docs :smiling_face:

I can also create an example repo to go along with it — it could live in meteor/examples alongside the other sample apps, as we discussed here. A minimal app showing the mail preview with accounts-password (verification, reset, enrollment) would make a good reference imo :saluting_face:

Let me know how you’d like to organize it!

1 Like

wow that is nice, have a time i dont see complete new user-features being added to meteor

100% sure, this is the best path, and as @grubba has said, we can add it in our docs before it be part of the core

2 Likes