Brief Overview of the new EmailComponent

This article is also available in the following languages:
By GreyCells
It's often more practical (read: maintainable) to use the built in components and much as I like SwiftMailer, I thought it best that I investigated Cake's core EmailComponent.
Big Note: The examples below are not intented for production servers, but just to give an idea of the files/code snippets needed to send email.

First create your email layouts. Create a default.ctp in the following directories:

views/layouts/email/text/

views/layouts/email/html/

The text layout (not a template):

View Template:


<?php echo $content_for_layout?>
and the html layout:

View Template:


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<body>
<?php echo $content_for_layout?>
</body>
</html>

This is a dummy controller for demonstration purposes only:

Controller Class:

<?php 
class MailerController extends AppController {

    var 
$name 'Mailer';
    
//Not using a model
    
var $uses '';
    
//The built in Cake Mailer
    
var $components = array('Email');
    

}
?>

Simple text Message

To send a simple text message (useful for alerts etc), you do not need templates. Example function for the dummy Mailer controller:

Controller Class:

<?php 
    
/**
     * Send a text string as email body
     */
    
function sendSimpleMail() {
        
$this->Email->to 'yourlogin@localhost';
        
$this->Email->subject 'Cake test simple email';
        
$this->Email->replyTo 'noreply@example.com';
        
$this->Email->from 'Cake Test Account <noreply@example.com>';
        
//Set the body of the mail as we send it.
        //Note: the text can be an array, each element will appear as a
        //seperate line in the message body.
        
if ( $this->Email->send('Here is the body of the email') ) {
            
$this->Session->setFlash('Simple email sent');
        } else {
            
$this->Session->setFlash('Simple email not sent');
        }
        
$this->redirect('/');
    }
?>
This can be called from http://localhost/mailer/sendSimpleMail - if all is OK, you should receive an email just by visiting the URL.

Pretty easy so far. Note: by default Cake EmailComponent uses the built in php mail() function, so if you are having problems, please ensure you can use that function successfully directly from a php script.

The mail function used by $this->Email->send() can be set via $this->Email->delivery to 'mail' or 'smtp', but I have only tested 'mail' (the default).

Text Message from a Template

Templates for emails are stored by default in views/element/email/text or views/elements/email/html

Create the following template in views/elements/email/text/test.ctp:

View Template:


Here is the template body text.

<?php echo $someValue?>


And the function for the dummy controller:

Controller Class:

<?php 
    
/**
     * Use a layout for the message body
     * Create the following files:
     * views/elements/email/text/test.ctp
     * 
     * containing: the layout you want for your email
     *
     */
    
function sendTemplateMail() {
        
$this->Email->to 'yourlogin@localhost';
        
$this->Email->subject 'Cake test template email';
        
$this->Email->replyTo 'noreply@example.com';
        
$this->Email->from 'Cake Test Account <noreply@example.com>';
        
$this->Email->template 'test';
        
//Set view variables as normal
        
$this->set('someValue''Cake tastes good today');
        
//Do not pass any args to send()
        
if ( $this->Email->send() ) {
            
$this->Session->setFlash('Template email sent');
        } else {
            
$this->Session->setFlash('Template email not sent');
        }
        
$this->redirect('/');
        
    }
?>

Nothing very new here, just set view variables as you would normally (they are shared across all views). If you expect to have lots of email templates (elements), then you can organize them within sub-directories of view/elements/email/text and view/elements/email/html then prefix 'mydir/' to the $this->Email->template value. e.g.: $this->Email->template = 'mydir/test'.

Html Message from a template

Cake's Mail component supports 'text', 'html' or 'both' styles of email. The default is (quite rightly) 'text' and can be changed via $this->Email->sendAs().


Create the following template in views/elements/email/text/test2.ctp:

View Template:


Here is the template body text for test2.

<?php echo $someValue?>

and views/elements/email/html/test2.ctp:

View Template:


<h2>
Here is the template body text.
</h2>
<p><em><?php echo $someValue?></em></p>


Example function for our dummy Mailer controller:

Controller Class:

<?php 
    
/**
     * Use a layout for the message body
     * Create the following files:
     * views/elements/email/html/test2.ctp
     * views/element/email/text/test2.ctp
     * 
     * containing: the layouts you want for your email
     *
     */
    
function sendTemplateHtmlMail() {
        
$this->Email->to 'yourlogin@localhost';
        
$this->Email->subject 'Cake test template email';
        
$this->Email->replyTo 'noreply@example.com';
        
$this->Email->from 'Cake Test Account <noreply@example.com>';
        
$this->Email->template 'test2';
        
//Send as 'html', 'text' or 'both' (default is 'text')
        
$this->Email->sendAs 'both';
        
//Set view variables as normal
        
$this->set('someValue''Cake and cream is good for you');
        
//Do not pass any args to send()
        
if ( $this->Email->send() ) {
            
$this->Session->setFlash('Template html email sent');
        } else {
            
$this->Session->setFlash('Template html email not sent');
        }
//        $this->redirect('/');
        
    
}

?>

That's all there is to it. Cake's EmailComponent is also able to handle attachments, but that is for a later date.

The last function did not work until I had 'fixed' a few things in email.php. See https://trac.cakephp.org/ticket/1851 if you want to play now.




Comments

  • Posted 07/01/10 03:44:59 PM
    i followed the steps from the new EmailComponent tutorial !!

    $this->Email->send() always returns false !!!!

    Any ideas? Thanks in advance
  • Posted 08/31/09 06:52:21 AM
    This function always return false. I'm using xampp+mercury under windows to send email. Should I doing some configuration for mercury to send email?
  • Posted 08/28/09 09:14:25 AM
    I HIGHLY recommend using

    $this->Email->delivery = 'smtp';

    otherwise you may have the same problem many people seem to having - emails not sending to certain addresses.
  • Posted 05/09/09 02:03:04 PM
    Great article!

    Embedding your display images for HTML, and using the "cid:" syntax to reference them, is a great way for your emails to be more tolerant of spam filters. But the EmailComponent isn't setting the Content-ID header for attachments, so the images don't render in all clients (e.g., MS Outlook works, but GMail doesn't). With a small change to email.php you can fix this easily though.

    I've opened a ticket (https://trac.cakephp.org/ticket/6358) to track this; check it out for details.
  • Posted 03/15/09 02:44:33 AM
    Hi,

    The mail sending doesnt work while sending mail in sendAs = 'both'
    I removed the @ to see what mail() is complaining about.
    Warning (2): mail() [function.mail]: Bad parameters to mail() function, mail not sent. [CORE/cake/libs/controller/components/email.php, line 656]
    I have posted the mail data which is being sent to cakebin. The url is http://bin.cakephp.org/view/26733214
    thanks

  • Posted 07/27/08 09:15:17 AM
    Was a piece of cake (no pun intended) to set up. Very clear and straightforward, thanks!

    - Jesse
    http://www.jessefreeman.com http://www.flashartofwar.com
  • Posted 02/14/08 03:19:17 PM
    Everything works as advertised except the emails don't get received by aol, hotmail, and various other mail servers that require a reverse dns lookup since it's sending from my local server. I can't seem to get the smtp to work sending out through gmail. Any ideas?

    ** EDIT: Nevermind, this was actually a reverse DNS issue with my server. If you find that you are having issues sending to certain email addresses you can check your reverse dns for your server here: http://postmaster.info.aol.com/tools/rdns.html **

    @Rob: what are you using for line breaks? I've been using \\n in my mail content and it seems to translate correctly.
  • Posted 12/25/07 03:51:06 PM
    Hey,

    i just wanna say thank you for the tut, i've tried it and everything worked as you have described!!

    if anyone has questions, please ask and i will try to help out.

    Joren
  • Posted 11/05/07 05:40:17 PM
    with text formatted email.. does anyone know why one line break in my template turns into two line breaks when it gets recieved by the user.

    it's like i have a choice.. two line breaks or none.. :(
  • Posted 09/26/07 03:29:20 PM
    Thanks for the guide. What's the best way to validate some fields before sending the email? For example, if my form requires a name and a valid email, would I make a model for it? And I want the form to redisplay with the entered values if it fails validation.
  • Posted 06/05/07 06:13:11 AM
    I've tried to send a simple email following thedirections in this article, also set template = null, but no mail gets send, Email->send returns false. I can however on the same server send an email using PHP's mail() function.

    I've downloaded cake_1.2.0.5146alpha.zip yesterday, replaced the cake folder of the cake_1.1.14.4797 installation. All's well except that the email component doesn't send mail.

    What I've done:

    1. There's a default.ctp in app/views/layouts/email/html and app/views/layouts/email/text.
    2. Created the mailcontroller:

    class MailerController extends AppController {

    var $name = 'Mailer';
    var $uses = '';
    var $components = array( 'Email' );


    function sendSimpleMail() {

    $this->Email->to = 'romano@iblis.demon.nl';
    $this->Email->subject = 'Cake test simple email';
    $this->Email->replyTo = 'noreply@adomain.com';
    $this->Email->from = 'Cake Test Account ';
    $this->Email->template = null;

    if ( $this->Email->send('Here is the body of the email') ) {
    // $this->Session->setFlash('Simple email sent');
    // exit( 'ja' );
    }
    else {
    // $this->Session->setFlash('Simple email not sent');
    // exit( 'nee' );
    }
    $this->redirect('/');
    }
    }


    Called the action via the url.

    Any ideas where I might find the solution to this problem?

    Best regards,
    Romano
    • Posted 06/06/07 05:00:36 AM
      To reply to my own message above, the problem seems to be that the fifth parameter in PHP's mail() function cannot be used in safe mode. If I remove it from the Email components __mail function, all works fine.

      Ciao,
      Romano
  • Posted 04/17/07 11:02:20 AM
    The article states that templates are in views/layouts/email/* however the current version seems to want them in views/elements/email. Is this a recent change and will it stay that way?
    • Posted 04/17/07 05:22:49 PM
      The article states that templates are in views/layouts/email/* however the current version seems to want them in views/elements/email. Is this a recent change and will it stay that way?
      As far as I'm aware (i.e. my apps still work), nothing has changed wrt layouts and templates. The text and html layouts (for all mails) are still located in views/layouts/email/* and the individual templates (for each mail) are in views/elements/email/*

      ~GreyCells
  • Posted 04/03/07 08:37:29 AM
    In php4 using $this->set will not make your variable available to the email template. You will get an error in your sent email similar to:


    Notice: Undefined variable: aVariable in /blah/blah/user/htdocs/create/app/views/elements/email/text/invite.ctp on line 3

    To get over this you can use $this->Email->Controller->set() instead.
  • Posted 11/30/99 12:00:00 AM
    So does this solution have built in spam deterrent so I can use an email form on my website and not worry about it getting hijacked? Or do I need to filter the users input and would that be something I would handle with the sanitizer in cake?

    Huey
  • Posted 11/30/99 12:00:00 AM
    Thanks for the great tutorial, GreyCells! It came at the perfect time for me.

    In the tutorial you warn that:
    "The examples below are not intented for production servers"
    and: "This is a dummy controller for demonstration purposes only."

    What's wrong with using this code for a production server? Besides continuing to tailor the code to our own application, is there something wrong with using the example code as is? Could you list the things you would recommend shoring up before releasing this code into the wild?

    Many thanks!
    Robin
  • Posted 11/30/99 12:00:00 AM
    Also, the EmailComponent looks like a great alternative to SwiftMailer. Can anyone offer some suggestions on why a CakePHP app would use SwiftMailer instead?

    Many thanks!
    Robin
  • Posted 11/30/99 12:00:00 AM
    Robin - The sample code has not been written with a production environment in mind, so has not been fully tested, parameters are not sanitized etc. I would not recommend having a controller method that allows the world to generate email without (at least) some form of logging/authentication/throttling. I would also recommend using Cake's Security component (http://manual.cakephp.org/chapter/security) and to read 'How to break Web Software' by Andres and Whittaker.

    Which sort of answers Huey/Jeff's question. I'm not a big fan of captcha's etc because of accessability issues, although they do have their place. There is a lot you can do to mitigate the risk if you implement a simple IP address based throttling system and use Cake's security component.

    Robin - Why use SwiftMailer? Well, it's a mature, feature complete library that allows you to very easily do things such as attachments etc. I'm sure Cake's mail component will match the features and stability soon, but don't forget 1.2 is still in heavy development.

    ~GreyCells
  • Posted 11/30/99 12:00:00 AM
    In newer versions of the EmailComponent, the class attribute $template is defaulted to 'default'. This means that in order to use Email::send('Some simple text content') you must first explicitly set Email->template = null;

    See: https://trac.cakephp.org/ticket/2105
    ~GreyCells

Comments are closed for articles over a year old