PHPMailer with native API for PHP 5.x

By Heiner Gassen (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:

Download code <?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:

Download code <?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 108

CakePHP Team Comments Author Comments
 

Bug

1 typo

There is a typo here:
<code>$this->Mailer->errorInfo; </code>
should be:
<code>$this->Mailer->ErrorInfo; </code>
Posted Nov 25, 2006 by Marcin
 

Comment

2 Typo corrected

Thank you! I corrected the typo in the code.
Posted Dec 31, 1969 by Heiner Gassen
 

Question

3 Sending a value to the mail template

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 Dec 31, 1969 by Rick Jones
 

Bug

4 One more tiny typo

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

should be

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

thanks for the example !
Posted Dec 31, 1969 by Sarah King
 

Question

5 PHP4

Anyone know how to implement this with PHP4? I'm guessing I need to use the overload() function somewhere :S
Posted Dec 31, 1969 by Rick Jones
 

Comment

6 PHP4

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 Dec 31, 1969 by Jose M. Navas
 

Question

7 templates

Where do the email templates exactly go? And how do these work ?
Posted Dec 31, 1969 by chris
 

Bug

8 error

Also there is an error on line 33.. ) should be }
Posted Dec 31, 1969 by chris
 

Comment

9 Fixed

Also there is an error on line 33.. ) should be }

I fixed it, thank you for reporting.
Posted Apr 10, 2007 by Heiner Gassen
 

Question

10 Why so complicated

Controller Class:

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

    class 
MailerComponent extends PHPMailer
    
{}
?>

Now its possible to use component exactly like PHPmailer object.
Posted Apr 17, 2007 by Grzegorz Pawlik
 

Comment

11 I can see why you would want to use the delegator pattern

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 May 17, 2007 by Rich Yumul
 

Question

12 html code in email

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 Jul 29, 2007 by Salim
 

Comment

13 set the type to HTML

do this before your send it:


    $this->Mailer->IsHtml(true);
Posted Jul 30, 2007 by Rich Yumul
 

Question

14 Redirecting

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 Nov 22, 2007 by Justin Anders
 

Comment

15 Layout not shown



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 Nov 23, 2007 by Juan Paredes
 

Comment

16 Layout white

I have the same problem, after call ob_get_clean() a white page.
Posted Mar 4, 2008 by Igor Felluga
 

Comment

17 Found the error

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 Mar 5, 2008 by Igor Felluga
 

Comment

18 Cakephp 1.2 RC1

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 Jun 16, 2008 by Siebren Bakker
 

Comment

19 Rendering Problem Solution

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 Jun 26, 2008 by Antonie Potgieter