Sending Email With PHPMailer
[This is a slightly updated copy of the tutorial on now defunct wiki.cakephp.org]
This example will show you how to send HTML mail from you Cake application with PHPMailer.
You will create:
1. cakePHP component
2. a vendor package
3. view for plain text email body
4. view for HTML email body
5. a function in your controller to send mail.
This example will show you how to send HTML mail from you Cake application with PHPMailer.
You will create:
1. cakePHP component
2. a vendor package
3. view for plain text email body
4. view for HTML email body
5. a function in your controller to send mail.
Steps
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.thtml
Create component
- Create new component email. Paste the following code into app/controllers/components/email.php
Component Class:
Download code
<?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 = 'phpmailer@cakephp';
var $fromName = "Cake PHP-Mailer";
var $smtpUserName = ''; // SMTP username
var $smtpPassword = ''; // SMTP password
var $smtpHostNames= ""; // specify main and backup server
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;
}
function bodyText() {
/** This is the body in plain text for non-HTML mail clients
*/
ob_start();
$temp_layout = $this->controller->layout;
$this->controller->layout = ''; // Turn off the layout wrapping
$this->controller->render($this->template . '_text');
$mail = ob_get_clean();
$this->controller->layout = $temp_layout; // Turn on layout wrapping again
return $mail;
}
function bodyHTML() {
/** This is HTML body text for HTML-enabled mail clients
*/
ob_start();
$temp_layout = $this->controller->layout;
$this->controller->layout = 'email'; // HTML wrapper for my html email in /app/views/layouts
$this->controller->render($this->template . '_html');
$mail = ob_get_clean();
$this->controller->layout = $temp_layout; // Turn on layout wrapping again
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()
{
vendor('phpmailer'.DS.'class.phpmailer');
$mail = new PHPMailer();
$mail->IsSMTP(); // set mailer to use SMTP
$mail->SMTPAuth = true; // turn on SMTP authentication
$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 = 50; // 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->subject;
$mail->Body = $this->bodyHTML();
$mail->AltBody = $this->bodyText();
$result = $mail->Send();
if($result == false ) $result = $mail->ErrorInfo;
return $result;
}
}
?>
Useing it in your controller
Controller Class:
Download code
<?php
class MyController extends AppController{
var $components = array('Email'); // use component email
...
function send() {
$this->Email->template = 'email/confirm';
// You can use customised thmls or the default ones you setup at the start
$this->set('data', $data);
$this->Email->to = 'someone@somewhere.com';
$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();
//the rest of the controller method...
}
}
?>
Credits
This is lifted almost word for word from the original piece at http://wiki.cakephp.org/tutorials:sending_email_with_phpmailer but i figured as i was about to use it, i would rewrite it for the bakery.
Enjoy.
Drayen.
Comments
Comment
1 This is nice but...
Comment
2 Native PHPMailer API
Comment
3 SwiftMailer
;)
tut coming soon
Comment
4 Add Multiple Addresses.
1. Put the folowing line inside your controller action:
$this->Email->attach_to($to_address, $to_name);
/*Add this line as many times as you want.*/
2. Add the following to the email component.
//Initialize variable
var $to_arr = null;
//Add function
function attach_to($to_address, $to_name = '') {
if (empty($this->to_arr)) {
$this->to_arr = array();
$this->to_arr[0]['to_address'] = $to_address;
$this->to_arr[0]['to_name'] = $to_name;
} else {
$count = count($this->to_arr);
$this->to_arr[$count+1]['to_address'] = $to_address;
$this->to_arr[$count+1]['to_name'] = $to_name;
}
}
//Add this loop within the send function
if (!empty($this->to_arr)) {
foreach ($this->to_arr as $to) {
$mail->AddAddress($to['to_address'], $to['to_name']);
}
}
Thats it hope it helps someone out.
~Gene Kelly
Question
5 What is the data variable in controller
Thanks.
Comment
6 Re What is the data variable in controller
You can call it whatever you want.
For example, for a purchase confirmation email, you might list the products purchased in the emails, so you might use:
$products = $this->Session->read('shopping_basket');
$this->set('products',$products);
or something like that.
Comment
7 Other port usage
"Language string failed to load: recipients_failed"
It happens when you have smtp on other port then 25 (in my case it was port 26). So I put one more variable to email component class:
<code>
var $smtpHostPort= "26";
</code>
And a line to function send()
<code>
$mail->Password = $this->smtpPassword;
</code>
Comment
8 Language string failed to load
is the result of that the PHPmailer class cannot locate its language files when placing the complete class in the vendors directory. Moving the complete languages folder of the PHPmailer directory into the webroot of CakePHP fixes the problem.
Although I'm still strugling with a SMTP error, at least I do now receive the correct error :*(
Comment
9 Call to undefined method stdClass send
Fatal error: Call to undefined method stdClass::send() in F:\xampplite
\htdocs\cake\app\controllers\users_controller.php
turned out that I had declared
var $components = array('email');
NOT!!
var $components = array('Email');
Just thought I'd post in case anyone else was as daft as me :-).
Question
10 Error
fsockopen(): unable to connect to :25 in /home/content/i/m/r/imranbaran/html/app/vendors/phpmailer/class.smtp.php on line 105
please help
Comment
11 HTML layout not rendering
I do have one problem though, the HTML layout - app/views/layouts/email.thtml simply isn't rendering and I can't work out why.
The emails are sent perfectly just without the layout wrapped around them. I was hoping somebody else had experienced the same problem and found a solution.
Thanks
Question
12 SMTP data in config file
how can i declare smtp data (host,user,pass,port) in a config file, so the component reads it from config/email.php for example?!
cheers,
stefan
Comment
13 RE SMTP data in config file
The easiest thing to do is just add these values in your app/config/core.php file e.g.
define('CAKE_EMAIL_USER', 'website@mywebsite.com');
Then in the mailer component you just reference these values:
class EmailComponent
{
/**
* Send email using SMTP Auth by default.
*/
var $from = 'phpmailer@cakephp';
var $fromName = "Cake PHP-Mailer";
var $smtpUserName = CAKE_EMAIL_USER; // SMTP username
This way you've set the default values, but you can still over ride them when you use the component.
Question
14 Spam Vulnerability
Comment
15 re Spam Vulnerability
http://www.digital-web.com/articles/bulletproof_contact_form_with_php/
Bug
16 headers already sent
Warning: Cannot modify header information - headers already sent by (output started at /home/visioniz/public_html/books/app/controllers/components/email.php:114) in /home/visioniz/public_html/books/cake/libs/controller/controller.php on line 447
The funny thing is, I receive the sent emails, no problem, but cake can't render the page.
Please help.
Question
17 Attachment file location
$this->Email->attach($fully_qualified_filename, optionally $new_name_when_attached);
What will I use instead of $fully_qualified_filename. Example please.
Thanks in advance.
Comment
18 HTML layout not rendering
app/views/layouts/email.thtml:
View Template:
<?php
echo $content_for_layout;
?>
Question
19 Arabic Emails
i try to chag the $CharSet variable in class.phpmailer.php file to 'windows-1256' and no thing happened, then i try to to put a meta tag in my view : <?php echo $html->charset('windows-1256');?>
and also no thing happened, finally i try to use header() function in the beforeRender function in my controller : header('Content-Type:text/html; charset=windows-1256'); and also no thing happened the characters is still like ���Ö ��....... !!!!! -- :-( .. any can help me please...
Thanks a lot.
Comment
20 cakephp 1.2 compatibility
I encountered an issue when I tried to use your code with cakephp 1.2
It seems that the solution is to catch the rendering by an other way
$mail = $this->controller->render($this->template . '_text');$this->controller->output = '';
I don't know really why, but ob_start doesn't work for me.
If someone can confirm the problem ? or find an other solution !