Sending nice emails from any website is always fun, as we all know PHP has some very basic mail functionality that everyone has extended in their own way. I was trying to add email functionality to a site that I am developing and when I googled for anything to help I found this post from Alex McFayden that had a way to integrate PHPMailer into CakePHP as a component for any controller. Unfortunately it was written in 2006 for a previous version, obviously some changes were needed, so here are the new integration methods.
Get PHPMailer
- Get PHPMailer http://phpmailer.sourceforge.net/
- Unpack it into app/vendors/phpmailer/ , so you'll have /vendors/phpmailer/class.phpmailer.php etc.etc.
Create views and layouts
- Create two views, default_html.thtml and default_text.thtml and place them in app/views/your_controller/email/
- Create a layout for the HTML part of the email, call it app/views/layouts/email.ctp
Create component
- Create new component email. Paste the following code into app/controllers/components/email.php
<?php
/**
* This is a component to send email from CakePHP using PHPMailer
* @link http://bakery.cakephp.org/articles/view/94
* @see http://bakery.cakephp.org/articles/view/94
*/
class EmailComponent
{
/**
* Send email using SMTP Auth by default.
*/
var $from = 'some_email@goes.here.com';
var $fromName = "Displayed Name";
var $sitePrefix = '[MySite]';
var $useSMTPAuth = false;
var $smtpUserName = '';
var $smtpPassword = '';
var $smtpHostNames = "localhost:25";
var $text_body = null;
var $html_body = null;
var $to = null;
var $toName = null;
var $subject = null;
var $cc = null;
var $bcc = null;
var $template = 'email/default';
var $attachments = null;
var $controller;
function startup( & $controller)
{
$this->controller = & $controller;
}
/**
* Helper function to generate the appropriate template location
*
* @return string CakePHP location of the template file
* @param object $template_type
*/
function templateLocation($template_type)
{
return ('..'.DS.strtolower($this->controller->name).DS.$this->template.$template_type);
}
/**
* Renders the content for either html or text of the email
*
* @return string Rendered content from the associated template
* @param object $type_suffix
*/
function bodyContent($type_suffix)
{
$temp_layout = $this->controller->layout; // store the current controller layout
if ($type_suffix == 'html')
$this->controller->layout = '..'.DS.'email';
else
$this->controller->layout = '';
$mail = $this->controller->render($this->templateLocation('_'.strtolower($type_suffix)));
// render() automatically adds to the controller->output, we'll remove it
$this->controller->output = str_replace($mail, '', $this->controller->output);
$this->controller->layout = $temp_layout; // restore the controller layout
return $mail;
}
function attach($filename, $asfile = '')
{
if ( empty($this->attachments))
{
$this->attachments = array ();
$this->attachments[0]['filename'] = $filename;
$this->attachments[0]['asfile'] = $asfile;
} else
{
$count = count($this->attachments);
$this->attachments[$count+1]['filename'] = $filename;
$this->attachments[$count+1]['asfile'] = $asfile;
}
}
function send()
{
App::import('Vendor', 'PHPMailer', array ('file'=>'phpmailer'.DS.'class.phpmailer.php'));
$mail = new PHPMailer();
$mail->IsSMTP();
$mail->SMTPAuth = $this->useSMTPAuth;
$mail->Host = $this->smtpHostNames;
$mail->Username = $this->smtpUserName;
$mail->Password = $this->smtpPassword;
$mail->From = $this->from;
$mail->FromName = $this->fromName;
$mail->AddAddress($this->to, $this->toName);
$mail->AddReplyTo($this->from, $this->fromName);
$mail->CharSet = 'UTF-8';
$mail->WordWrap = 80; // set word wrap to 50 characters
if (! empty($this->attachments))
{
foreach ($this->attachments as $attachment)
{
if ( empty($attachment['asfile']))
{
$mail->AddAttachment($attachment['filename']);
} else
{
$mail->AddAttachment($attachment['filename'], $attachment['asfile']);
}
}
}
$mail->IsHTML(true); // set email format to HTML
$mail->Subject = $this->sitePrefix.' '.$this->subject;
$mail->Body = $this->bodyContent('html');
$mail->AltBody = $this->bodyContent('text');
$result = $mail->Send();
if ($result == false)
$result = $mail->ErrorInfo;
return $result;
}
}
?>
Then, to use this component you can do the following in your controller ...
var $components = array('Email');
function send_verification($id)
{
$this->Email->template = 'email/default';
$this->set('data', $this->data);
$toUser = $this->User->find(array('User.id'=>$id));
$this->Email->to = $toUser['User']['email'];
$this->Email->subject = 'Your new account';
//$this->Email->attach($fully_qualified_filename, optionally $new_name_when_attached);
// You can attach as many files as you like.
$result = $this->Email->send();
}
I've tested it and it works even when used from another function in the same controller being called as a JSON or XML action extension.