Generate mails with Twig

Yesterday, I discovered a new way for generating mails with Twig, in a very powerful way.

The problem

It started because of someone explaining me he was using something similar to this:

<?php
// Subject was loaded from a yaml file
$subject = 'Welcome to newsletter, %%customer_name%%';

$values = array(
   '%%customer_name%%' => $customer->getName(),
   '%%customer_mail%%' => $customer->getMail()
   // ...
);

foreach ($values as $name => $value) {
   $subject = str_replace($name, $value, $subject);
}
```php

For generating the content of the mail, it was something like this:

```php
<?php
$twig = $this->get('twig'); // a Twig_Environment instance
$bodyHtml = $twig->render('mail_newsletter.html.twig');
$bodyText = $twig->render('mail_newsletter.text.twig');

The problem with this solution is that you have two different types of templating engine. The first one is a PHP str_replace templating engine and the second one is Twig.

After some searches, I finally discovered a powerful way for generating mails:

The solution

First, you need to create a template, let's assume mail.twig:

{% block subject 'Welcome to newsletter, ' ~ customer.getName() %}

{% block body_html %}
   This is the <strong>HTML body</strong>.
{% endblock %}

{% block body_text %}
   This is the text body.
{% endblock %}

This is perfect: in one file, we have every informations for generating the mail content.

Let's see now how to fetch it from Twig:

<?php
$twig = $this->get('twig'); // Twig_Environment

$template = $twig->loadTemplate('mail.twig');
$parameters  = array(
   'customer' => $customer
);

$subject  = $template->renderBlock('subject',   $parameters);
$bodyHtml = $template->renderBlock('body_html', $parameters);
$bodyText = $template->renderBlock('body_text', $parameters);

And now, you have everything for creating your mail message, created from one file only.

This also means you can use in your template every Twig possibilities, like the translation extension, or the inheritance mechanism of templates.

Integration in your application

Now, we have a raw PHP implementation, let's see how it's possible to integrate it in your application.

The idea is to create a class for preparing the Swift message, so in the end we only need to set the receiver, and that's all!

A mail generator :

<?php
class TwigMailGenerator
{
   protected $twig;

   public function __construct(Twig_Environment $twig)
   {
       $this->twig = $twig;
   }

   public function getMessage($identifier, $parameters = array())
   {
       $template = $this->twig->loadTemplate('mail/'.$identifier.'.twig'); // Define your own schema

       $subject  = $template->renderBlock('subject',   $parameters);
       $bodyHtml = $template->renderBlock('body_html', $parameters);
       $bodyText = $template->renderBlock('body_text', $parameters);

       return Swift_Message::newInstance()
           ->setSubject($subject)
           ->setBody($bodyText, 'text/plain')
           ->addPart($bodyHtml, 'text/html')
       ;
   }
}

For using it, very simple: suppose you have organized your mails according to the schema mail/<identifier>.twig, the code to use it would be:

<?php
$twig = $this->get('twig');     // Twig_Environment
$mailer = $this->get('mailer'); // Swift_Mailer

$generator = new TwigMailGenerator($twig); // Can be in a DIC

$message = $generator->getMessage('newsletter', array(
   'customer' => $customer
));

$message->setTo($customer->getMail());
$mailer->send($message);

That's all for the suggested implementation! No need to create a dedicated bundle for it, or some kind of reusable code. There are 20 lines of code, just integrate it in your application to fit your needs, and it's enough.

Enjoy Twig!