PHPMailer with native API for PHP 5.x

This article is also available in the following languages:
By kitten
This tutorial on using PHPMailer with Cake (http://bakery.cakephp.org/articles/view/94) has a comment requesting a component that lets you use the native PHPMailer API. This is possible with PHP5's built-in overloading capabilities.
The Mailer component acts as a delegator and looks like this:

Component Class:

<?php 
class MailerComponent extends Object
{     
    
/**
     * PHPMailer object.
     * 
     * @access private
     * @var object
     */
     
var $m;    
    
    
/**
     * Creates the PHPMailer object and sets default values.
     * Must be called before working with the component!
     *
     * @access public
     * @return void
     */
    
function init()
    {
        
// Include the class file and create PHPMailer instance
        
vendor('phpmailer/class.phpmailer');
        
$this->= new PHPMailer;
        
        
// Set default PHPMailer variables (see PHPMailer API for more info)
        
$this->From 'me@example.com';
        
$this->FromName ='MyName';
        
// set more PHPMailer vars, for smtp etc.
     
}

    function 
__set($name$value)
    {
        
$this->m->{$name} = $value;
    }
    
    function 
__get($name)
    {
        if (isset(
$this->m->{$name})) {
            return 
$this->m->{$name};
        }
    }
             
    function 
__call($method$args)
    {
        if (
method_exists($this->m$method)) {
            return 
call_user_func_array(array($this->m$method), $args);
        }
    }
}
?>

In your controller, do the following:

Controller Class:

<?php 
    
var $components = array('Mailer');

    
// Inside your method:

    // Set up mail
    
$this->Mailer->init();
    
$this->Mailer->AddAddress('recipient@example.com');
    
$this->Mailer->Subject 'My Subject';
    
// Set PHPMailer vars and call PHPMailer methods (see PHPMailer API for more info)
    
    // Set mail body
    
ob_start();
    
$this->render('nameOfEmailTemplate''nameOfEmailLayout');
    
$this->Mailer->Body ob_get_clean();

    
// Send mail                            
    
if ($this->Mailer->send()) {
        echo 
'Mail was sent successfully.';
     } else {
        echo 
'There was a problem sending mail: '.$this->Mailer->ErrorInfo;
    }
?>

That's all! You can now call any PHPMailer method through $this->Mailer->MethodName() and set any class variable through $this->Mailer->varName = 'value'.

Comments

  • Posted 12/02/08 06:45:58 PM
    I have the RC3 running (1.2)
    but no matter what i do, it does not work

    either i get a plain text result like this:
    (sent by mail):

    From: MyName Message-ID: <5bb25ffb38af3456dae5a4887d3bda5c@....de> X-Priority: 3
    X-Mailer: PHPMailer (phpmailer.codeworxtech.com) [version 2.3] MIME-Version: 1.0
    Content-Transfer-Encoding: 8bit
    Content-Type: text/plain; charset="utf-8"

    or some error error trying to get some template to work:

    Indirect modification of overloaded property MailerComponent::$controller has no effect

    etc..

    has anybody a full working phpmailer component running?
    maybe even with some example calls
    would be very helpful
    thx
  • Posted 07/26/08 04:12:40 PM
    Antonie's solution above worked great. However I wasn't sure what the $this->data variable represented in his _render() call. Since getBody is located in my MailerComponent, $this->data was undefined resulting in an error.

    I replaced $this->data with $this->controller->viewVars to effectively gain access to any view variables in my email layout.

    Works great, thanks for all the good posts!
  • Posted 06/26/08 07:03:41 PM
    Hi there,

    For those of you whom have been having the rendering issue with the blank emails going through due to a glitch somewhere with the output buffering, please have a look at my code below.

    function getBody() {
        $temp_layout = $this -> controller -> layout;
        $this -> controller -> layout = '';
        
        ob_start();
        $this -> controller -> autoRender = false;
        
        App::import('Core', array('View'));
        $viewClass = new View($this -> controller);
        $this -> template = $viewClass -> _getViewFileName($this -> template);
        $content = $viewClass -> _render($this -> template, $this -> data);
        echo $viewClass -> renderLayout($content, 'email');
        
        $this -> controller -> autoRender = 'auto';
        $body = ob_get_clean();
        
        $this -> controller -> layout = $temp_layout;
        
        return $body;
    }

    It might not be the right way to solve the issue but at least it works fine. I'm in a hurry to get my site fixed right now, but might digg in a bit more later on in order to pinpoint the actual issue.

    All the best,
    Antonie
  • Posted 06/16/08 07:17:03 PM
    Has anyone gotten this to work with the RC1 release?
    I've gotten pretty much everything working, except one major part.
    When it sends out emails, the subject and body are completely blank?

    Here's my component:

    Component Class:

    <?php 
    <?php
    class MailerComponent extends Object
    {
        
    /**
         * PHPMailer object.
         *
         * @access private
         * @var object
         */
         
    var $m;
         var 
    $controller;
        
    /**
         * Creates the PHPMailer object and sets default values.
         * Must be called before working with the component!
         *
         * @access public
         * @return void
         */
        
    function init()
        {
            
    // Include the class file and create PHPMailer instance
            
    App::import('Vendor''PHPMailer', array('file' => 'phpmailer'.DS.'class
            $this->m = new PHPMailer;

            // Set default PHPMailer variables (see PHPMailer API for more info)
            $this->From = '
    verification@aevumdecessus.com';
            $this->FromName ='
    Aevum Decessus Administration';
            // set more PHPMailer vars, for smtp etc.

            $this->IsSMPT();
            $this->SMTPAuth = true;
            $this->Host = '
    aevumdecessus.com';
            $this->Username = '
    verification';
            $this->Password = '
    aS$h0l3';
         }
        function setBody($template, $layout)
        {
            $this->Body = $this->_render($template.'
    _html', $layout.'_html');
            $this->AltBody = $this->_render($template.'
    _text', $layout.'_text');
        }

        function _render($template, $layout)
        {
            ob_start();
            $this->controller->autoRender = false;
            $this->controller->render($template, $layout);
            $this->controller->autoRender = '
    auto';
            return ob_get_clean();
        }
        function __set($name, $value)
        {
            $this->m->{$name} = $value;
        }

        function __get($name)
        {
            if (isset($this->m->{$name})) {
                return $this->m->{$name};
            }
        }

        function __call($method, $args)
        {
            if (method_exists($this->m, $method)) {
                return call_user_func_array(array($this->m, $method), $args);
            }
        }
    }
    ?>
    ?>

    and my controller:

    Controller Class:

    <?php 
                                    $this
    ->User->set($this->data);
                                    
    $this->Mailer->controller = &$this;
                                    
    $this->Mailer->init();
                                    
    $this->set('token'$this->data['User']['email_token']);
                                    
    $emails $this->data['User']['email'];
                                    
    $this->Mailer->AddAddress($emails);
                                    
    $this->Mailer->Suject 'Please Validate your account';
                                    
    $this->Mailer->setBody('/email/validation''email');
                                    if (
    $this->Mailer->send())
                                    {
                                    
    $errors $this->Mailer->ErrorInfo;
                                    
    //$this->User->save();
                                    
    }
                                    else
                                    
    $errors 'Error Sending: '.$this->Mailer->ErrorInfo;
                                    
    $this->set('errors'$errors);
    ?>
  • Posted 03/05/08 03:41:24 AM
    The class must stop the Autorender e restart after the buffer

    <?php
        
    function _render($template,$layout) {
            
    ob_start();
            
    $this->controller->autoRender false;
            
    $this->controller->render($template,$layout);
            
    $this->controller->autoRender 'auto';
            
    $mail ob_get_clean();
            return 
    $mail;
        }
    ?>
  • Posted 03/04/08 10:32:22 AM
    I have the same problem, after call ob_get_clean() a white page.
  • Posted 11/22/07 04:30:22 PM
    Thanks for the script, mail works great. One problem though is it displays a white page afterward the email gets sent off with the same URL. It's like it is using the flash() function but it isn't. When I take out the mail code I don't run into this problem.

    Do you know how I can prevent this from happening?
  • Posted 07/30/07 12:11:13 PM
    do this before your send it:


        $this->Mailer->IsHtml(true);
  • Posted 07/29/07 01:56:09 AM
    Hello,

    I am using your guide but ran into a problem.
    The email that i receive is the raw html code.

    How do I ensure that the actual html file is being sent and no t the raw code ?

    Thanks.
  • Posted 05/17/07 11:21:29 PM
    I can see why you'd want to setup your mailer component using the delegator pattern versus just extending the PHPMailer class: double inheritance. If you follow the pattern described in the article. then not only will your resulting component behave just like the PHPMailer class, but you'll also have access to the functions and fields in the superclass Object.

    For example, I added the following snippet to my version of the MailerComponent:

    Component Class:

    <?php 
       
    var $controller;

        function 
    startup(&$controller) {
          
    $this->controller $controller;
          
    $this->init();
        }

        
    /**
         * Set the body of the email
         */
        
    function setBody($template$layout 'email') {
          
    $this->Body $this->_render($template$layout);
        }

        
    /**
         * Set the AltBody, like for the text in HTML+TXT emails
         */
        
    function setAltBody($template$layout 'email') {
          
    $this->AltBody $this->_render($template$layout);
        }

        function 
    _render($template$layout) {
          
    ob_start();
          
    $this->controller->render($template$layout);
          return 
    ob_get_clean();
        }


    ?>
    • Posted 11/23/07 01:45:39 PM

      Component Class:

      <?php 

            ob_start
      ();
            
      $this->controller->render($template$layout);
            return 
      ob_get_clean();

      ?>

      Is your $layout shown properly with a plain text template/layout using render as above? I've tried and the template content is correct, but no layout is shown (perhaps it would have something to do with ob_get_clean() ending the output rendering prematurely?)

      Thanks a lot!
  • Posted 04/17/07 08:17:16 AM

    Controller Class:

    <?php 
    vendor
    ('phpmailer/class.phpmailer');

        class 
    MailerComponent extends PHPMailer
        
    {}
    ?>
    Now its possible to use component exactly like PHPmailer object.
  • Posted 11/25/06 03:26:26 AM
    There is a typo here:
    $this->Mailer->errorInfo; should be:
    $this->Mailer->ErrorInfo;
  • Posted 11/30/99 12:00:00 AM
    Thank you! I corrected the typo in the code.
  • Posted 11/30/99 12:00:00 AM
    I'm new to Cake. This article helped a lot, but can you tell me how I would go about sending a variable to the mail template (i.e. for a verification email)?

    Thanks :)
  • Posted 11/30/99 12:00:00 AM
    function __set($name, $value)
    {
    $this->m->{$name) = $value;
    }

    should be

    function __set($name, $value)
    {
    $this->m->{$name} = $value;
    }

    thanks for the example !
  • Posted 11/30/99 12:00:00 AM
    Anyone know how to implement this with PHP4? I'm guessing I need to use the overload() function somewhere :S
    • Posted 11/30/99 12:00:00 AM
      I do something like this with every function of PHPMailer I want to use, is probably not the best method but this way works in PHP5 too.

      For the methods

      function send()
      {
      return $this->m->send();
      }

      And for properties:

      function setBody($value)
      {
      return $this->m->Body = $value;
      }
  • Posted 11/30/99 12:00:00 AM
    after i figured out I needed the parameter:
    $this->Mailer = 'smtp';
    it worked like a charm. thanks man.
  • Posted 11/30/99 12:00:00 AM
    Where do the email templates exactly go? And how do these work ?
  • Posted 11/30/99 12:00:00 AM
    Also there is an error on line 33.. ) should be }
    • Posted 04/10/07 03:58:31 AM
      Also there is an error on line 33.. ) should be }
      I fixed it, thank you for reporting.

Comments are closed for articles over a year old