Email templates using Zend_Mail and Zend_View

In a recent project I was working on which was based on Zend Framework (ZF) I wanted to send out some fairly complex emails following user registrations and for various alerts. ZF has a decent class for sending emails which just left forming the text I wanted to send in each email. For each type of email much of the content would remain the same with just a few things changing like name and date. I could have mixed up these elements and strung them together in a variable. This would probably have become very messy very quickly in the same way that mixing html and logic together gets messy quickly.

The solution to the html/logic issue is to use templates and unsurprisingly the same approach also works well for email. There is no shortage of templating systems for PHP and I suspect most would work perfectly adequately for this task. As I was already using ZF though I decided to go with Zend_View.

The class which follows wraps Zend_Mail and Zend_View together. It's possible to quickly and simply assign variables to be used in the template and then when the time comes to send the email additional default variables can be included from a config file. The config file also includes the location where the templates are stored and the email address from which the email should be sent.

/**
 * A template based email system
 *
 * Supports the sending of multipart txt/html emails based on templates
 *
 *
 * @author Jonathan Street
 */
class Acai_Mail
{

    /**
     * Variable registry for template values
     */
    protected $templateVariables = array();

    /**
     * Template name
     */
    protected $templateName;

    /**
     * Zend_Mail instance
     */
    protected $zendMail;
     
    /**
     * Email recipient
     */
    protected $recipient;
    
    /**
     * __construct
     *
     * Set default options
     *
     */
    public function __construct ()
    {
        $this->zendMail = new Zend_Mail();

        

    }

    /**
     * Set variables for use in the templates
     *
     * Magic function stores the value put in any variable in this class for
     * use later when creating the template
     *
     * @param string $name  The name of the variable to be stored
     * @param mixed  $value The value of the variable
     */
    public function __set ($name, $value)
    {
        $this->templateVariables[$name] = $value;
    }

    /**
     * Set the template file to use
     *
     * @param string $filename Template filename
     */
    public function setTemplate ($filename)
    {
        $this->templateName = $filename;
    }
    
    /**
     * Set the recipient address for the email message
     * 
     * @param string $email Email address
     */
    public function setRecipient ($email)
    {
        $this->recipient = $email;
    }

    /**
     * Send the constructed email
     *
     * @todo Add from name
     */
    public function send ()
    {
        /*
         * Get data from config
         * - From address
         * - Directory for template files
         */
        $config = Zend_Registry::get('Config');
        $templateDir = $config->email->template->dir;
        $fromAddr = $config->email->from;
        $templateVars = $config->email->vars->toArray();

        foreach ($templateVars as $key => $value)
        {
            //If a variable is present in config which has not been set
            //add it to the list
            if (!array_key_exists($key, $this->templateVariables))
            {
                $this->{$key} = $value;
            }
        }
        
        //Build template
        //Check that template file exists before using
        $viewConfig = array('basePath' => $templateDir);
        $subjectView = new Zend_View($viewConfig);
        foreach ($this->templateVariables as $key => $value)
        {
            $subjectView->{$key} = $value;
        }
        try {
            $subject = $subjectView->render($this->templateName . '.subj');
        } catch (Zend_View_Exception $e) {
            $subject = false;
        }
        
        $textView = new Zend_View($viewConfig);
        foreach ($this->templateVariables as $key => $value)
        {
            $textView->{$key} = $value;
        }
        try {
            $text = $textView->render($this->templateName . '.txt');
        } catch (Zend_View_Exception $e) {
            $text = false;
        }
        
        $htmlView = new Zend_View($viewConfig);
        foreach ($this->templateVariables as $key => $value)
        {
            $htmlView->{$key} = $value;
        }
        try {
            $html = $htmlView->render($this->templateName . '.html'); 
        } catch (Zend_View_Exception $e) {
            $html = false;
        }

        //var_dump($subject);
        //var_dump($text);
        //var_dump($html);
        
        //Pass variables to Zend_Mail
        $mail = new Zend_Mail();
        //var_dump($fromAddr);
        $mail->setFrom($fromAddr);
        //var_dump($this->recipient);
        $mail->addTo($this->recipient);
        
        $mail->setSubject($subject);
        
        $mail->setBodyText($text);
        if ($html !== false) {
            $mail->setBodyHtml($html);
        }
        
        //Send email
        //$config = Zend_Registry::get('configuration');
        $transport = $config->email->transport;
        if($transport == 'Dev')
        {
            $tr = new Acai_Mail_Transport_Dev;
            $mail->send($tr);
            return;
        }
        $mail->send();
    }
    
}

You may want to make some changes to how the class fetches its default values depending on your setup.

Using the class is very simple. Here is the code I use to send a confirmation email to a new user.

$emailObj = new Acai_Mail;
$emailObj->setRecipient($data['email']);
$emailObj->setTemplate('register');
$emailObj->activationLink = $actiUri;
$emailObj->send();

Hopefully you find the above code of some use and can integrate it into your own projects. If you have any questions or suggestions please do post them in the comments below.