Jump to content

Turn Your Boring ProcessWire Emails into Beautiful Masterpieces! 🎨


bernhard
 Share

Recommended Posts

Ever felt like your ProcessWire emails look like they're stuck in 1999? You know the drill - sending emails is super easy with WireMail:

$m = new WireMail();
$m->from('foo@bar.com');
$m->to('xxx@yyy.com');
$m->subject('Hello there!');
$m->bodyHTML('<h1>This is great!</h1><p>I am an ugly mail...</p>');
$m->send();

But let's be honest - they look about as pretty as a website built with Microsoft FrontPage! πŸ˜…

Mv8sVRE.png

πŸͺ„ Enter the Mail Pimp Hook!

Drop this magical hook into your /site/ready.php (or even better Site.module.php), and watch your emails transform from ugly ducklings into beautiful swans:

<?php
$wire->addHookBefore('WireMail::send', function(HookEvent $event) {
  // double check that we got a wiremail instance
  // this also tells the IDE what $mail is (to get IntelliSense)
  $mail = $event->object;
  if (!$mail instanceof WireMail) return;
  
  // get current mail body
  $html = $mail->get('bodyHTML');
  if (!$html) return;
  
  // get email layout markup
  $layoutFile = wire()->config->paths->templates . 'mails/default.html';
  if (!is_file($layoutFile)) return;
  
  // replace ##content## with actual mail content
  $html = str_replace(
    '##content##',
    $html,
    wire()->files->render($layoutFile)
  );
  
  // write new body to mail
  $mail->bodyHTML($html);
});

 

yKOVv4D.png

The HTML

Just create a beautiful MJML template at /site/templates/mails/default.mjml, put ##content## where your email content should go, convert it to HTML and BOOM! πŸ’₯ Every email gets automatically wrapped in your gorgeous template.

No more CSS wrestling matches, no more "Why does this look different in Outlook?" headaches. Just pure email beauty, automagically! ✨

Now your clients will think you spent days crafting those emails, when in reality, you're sipping coffee while your hook does all the heavy lifting. Work smarter, not harder! πŸš€

#ProcessWire #EmailMagic #NoMoreUglyEmails

PS: This is the MJML template that I used:

<mjml>
  <mj-head>
    <mj-attributes>
      <mj-all font-family="Tahoma" />
      <mj-text line-height="140%" />
    </mj-attributes>
  </mj-head>
  <mj-body background-color="#efefef">
    <mj-section
      background-color="#ffffff"
      background-repeat="repeat"
      padding-bottom="30px"
      padding-top="30px"
      text-align="center"
    >
      <mj-column>
        <mj-image
          align="center"
          padding="25px"
          src="xxx"
          target="_blank"
          width="200px"
          alt="Logo"
        ></mj-image>
        <mj-text>##content##</mj-text>
      </mj-column>
    </mj-section>
    <mj-section>
      <mj-column>
        <mj-text
          font-size="10px"
          color="#a0a0a0"
          align="center"
        >
          powered by
          <a
            href="https://www.baumrock.com/"
            style="color: #158f66"
            >baumrock.com</a
          >
        </mj-text>
      </mj-column>
    </mj-section>
  </mj-body>
</mjml>

VSCode has an extension to get a live preview and export MJML to HTML:

HylErcF.png

And here are some other free templates: https://mjml.io/templates

I use https://www.base64-image.de/ to add the logo to my mail template as src="data:image/jpeg;base64,/9j/4QAWRXhpZgAATU0AKgAAAA..." to avoid headaches with image paths, remote assets blocking etc.

  • Like 13
  • Thanks 6
Link to comment
Share on other sites

  • 3 weeks later...
  • 3 weeks later...

Thanks @bernhard
in past I have used Cerberus as mentioned by @Jonathan Lahijani, but MJML is very awesome; expecially for the VScode extension with the html compiler. and preview.

I think the template could be used directly in the wire mail construct, (without the ready hook):

// ...
$m->bodyHTML(wire()->files->render($layoutFile));
// ...

Or do you think this is not a good practice?

Now I'm testing it dynamically with "placeholders" :

// get template
$bodyHTML = wire()->files->render($layoutFile);

// let's say we have 2 placeholders into the html template: one for user name as [[userName]] and one page body content as [[pageBody]]
$bodyHTML = str_replace(
["[[userName]]","[[pageBody]]"],
[ucfirst(wire('user')->name),$page->body],
$bodyHTML,
);
// ...
$m->bodyHTML($bodyHTML);
// ...

This works for me: it has great potential.
Many thanks again for sharing this solution.

Link to comment
Share on other sites

Hey @Cybermano glad it was helpful!

  21 hours ago, Cybermano said:
// ...
$m->bodyHTML(wire()->files->render($layoutFile));
// ...

Or do you think this is not a good practice?

Expand  

That's what I've been using before I had the idea of hooking into WireMail::send.

Everything in life has pro's and con's... So I'd not say it's a bad practise. But what I like about the solution is that it fits my credo "simple things should be simple".

Sending a beautiful thing should be simple. And what you show might look QUITE simple it's not as simple as my version. If you only have one mail it won't matter or your version would even be easier (because you see everything that is going on). But if you are sending mails from different places in different occasions (eg on registration, on a new post, on a schedule, etc...) then my version keeps your code DRY (don't repeat yourself) whereas your version either tempts the dev to copy and paste those lines of code or be too lazy and just send out an ugly 90s style email. Both is not ideal in my opinion and investing a little more time to setup the hook will be beneficial in the long run.

Also, while it's just a few lines of code, when your codebase grows every line of code that is not instantly and easily understandable matters. Your brain has to read the code, understand it, interpret it and remember it. With your str_replace that might be QUITE easy, but things add up and suddenly it might make the difference between easy to read code and a bloat of spaghetti code.

It's about building a habit.

Another problem with your solution is that if you copy&paste this to 3 spots, for example, and later you add another replacement tag, you have to do a search&replace and you might miss one spot and you introduce a bug. If you have it on a central place this can not happen.

On the other hand if you want to render different files or you want different tags for different emails your approach might be the better one. And for someone not familiar with your codebase it might be easier to understand your version vs. the hook, because only seeing the $mail->send() somewhat hides how the mail gets sent with nice HTML and your version makes that obvious.

  • Thanks 1
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
Γ—
Γ—
  • Create New...