Sending Email from the CakePHP Shell
Sending an email from a CakePHP shell may sound like a difficult task but, with the aid of a re-usable shell task, it's an easy feature to implement. In this article I will walk through the setup and creation of the shell task so that you can be sending emails in minutes.
Getting Started
The first thing you will need is a shell in which to use the email sending task. If you're not familiar with creating a shell I recommend you start by reading the section of the CakePHP manual on Creating Shells & Tasks. I will be using, for the purpose of demonstration, a simple shell that will send out an email in both HTML and plain text format. The task will make use of the CakePHP Email Component so if you're not familiar with how to use that I would suggest first reading that section in the manual.
Creating the Shell
The shell, as I mentioned, is quite simple and doesn't really offer a lot of functionality itself. The shell code, below, is not meant to be "production ready" but will serve as a base to build on and demonstrate the basic usage. Create the shell by saving the code below in the "/app/vendors/shells/" directory as "foo.php" (you can use a different name if you prefer, just remember to update the class name accordingly).
class FooShell extends Shell { /** * Load Tasks used by the shell * * @access public */ /** * Welcome message * * @access public */ public function _welcome() {} /** * Default shell process * This is called if no task is specified * * @access public */ public function main() { $this->out('Use the command: cake foo sendTestMail'); } /** * Send an email message using the Mail task * * @access public */ public function sendTestMail() { $recipient = ''; $subject = ''; $from = ''; $template = ''; /* Get the address to send to */ while($recipient == '') { $recipient = $this->in('Please enter the recipient address: '); } /* Get the subject */ while($subject == '') { $subject = $this->in('Please enter a subject line for the message: '); } /* Get the sender address */ while($from == '') { $from = $this->in('Please enter your (sender) email address: '); } /* Get the template to use */ $this->out('The email template you specify below must already exist in the /views/elements/email/html and /views/elements/email/text directories.'); $this->out('Enter the template name without the .ctp extension.'); while($template == '') { $template = $this->in('Please enter the name of the template to use: ', null, 'default'); } /** * If you want to use SMTP; uncomment the lines below and provide your SMTP server information. * Leave commented to use the PHP mail feature to send the email. */ /* $smtpOptions = array( 'host' => 'localhost', // your SMTP server 'username'=>'smtpUsername', // your SMTP account username 'password'=>'smtpPassword', // your SMTP account password 'port'=>'25', // SMTP server port to connect to. This key is optional. Default is 25. 'timeout'=>'15', // SMTP server timeout in seconds. This key is optional. Default is 15. ); $this->Mail->setSmtpOptions($smtpOptions); */ /** * Send the email */ $sent = $this->Mail->sendMail($recipient, $subject, $from, $template); } }
Creating the Shell Task
Once you have the shell setup, the next step is to create the shell task that will actually handle the sending of the email. This task isn't much more complicated than the sample shell presented above and makes use of the native CakePHP Email component to do most of the work of sending the email. The code presented here does not include any handling of attachments, to keep it simple, but that shouldn't be hard to work in.
The code below will give us our shell task for sending the email. Save this as "mail.php" in the "/app/vendors/shells/tasks/" directory. Here, again, you can use a different name but make sure to update the class name to match. Do not call it "Email" since this task uses the actual CakePHP Email Component and this leads to trouble (at least it did for me).
/* load a Controller for use by the Email component */ App::import('Core', 'Controller'); /* load the Email component */ App::import('Component', 'Email'); class MailTask extends Shell { /** * Controller used to access the view for sending mail * * @access private */ private $Controller = null; /** * CakePHP Email component * * @access private */ private $Email = null; /** * Default SMTP server options * * @access private */ 'port'=>'25', 'timeout'=>'15', 'host' => 'localhost', 'username' => 'smtpUsername', 'password' => 'smtpPassword', 'messageId' => true ); /** * User defined SMTP options * Associative array of options for smtp mailer (port, host, timeout, username, password) * * @access public */ /** * Mail sending errors * * @access public */ public $errors = null; /** * Constructor * Setup an empty Controller and the Email component * * @access public * @param object $dispatch Instance of the ShellDispatcher object that loaded this script. This is passed automatically by CakePHP. * @return void */ public function __construct(&$dispatch) { $this->Controller =& new Controller(); $this->Email =& new EmailComponent(null); $this->Email->Controller = $this->Controller; parent::__construct($dispatch); } /** * Main task function. Shells will call this method to start the task logic * * @access public */ public function execute() {} /** * Set the user defined SMTP server options * * @param array $options Array of SMTP server information * @return void */ } /** * Send an email message * * @param string $to Email address(es) to send the message to. Use comma separated list to send to multiple addresses. * @param string $subject Subject of the email message. * @param string $from Email address of the message sender. * @param string $template CakePHP email template to use for the message. * @param mixed $msgData Optional data to be passed to the email message template. Available in the template as $msgData; * @param string $sendAs Format to send the message as (text, html, both). Default is "both". * @param array $cc Optional array of email addresses to CC the message to. * @param array $bcc Optional array of email addresses to BCC the message to. * @param string $replyTo Email address to use as the "reply to" address. Default is the $from address. * @param string $return Optional email address to send bounce messages/errors to. Default is the $from address. * @param string $charset Character set to use when sending the email. Default is 'UTF8'. * @return bool True if the message is successfully sent, False if not */ public function sendmail($to, $subject, $from, $template, $msgData = null, $sendAs = 'both', $cc = null, $bcc = null, $replyTo = null, $return = null, $charset = 'UTF8') { /* reset the Email component */ $this->Email->to = $to; $this->Email->subject = $subject; $this->Email->from = $from; $this->Email->template = $template; $this->Email->sendAs = $sendAs; } } $this->Email->charset = $charset; /* If there is a host/username/password set use SMTP else use Mail */ $this->Email->smtpOptions = $this->smtpOptions; $this->Email->delivery = 'smtp'; } else { $this->Email->delivery = 'mail'; } /* Set the message data in the controller to make it available to the template */ /* send the email */ $sent = $this->Email->send(); /* Store sending errors if using SMTP */ $this->errors = $this->Email->smtpError; } return $sent; } }
Putting It All Together
Now that we have the shell and the task ready to go we can put them to use sending our emails. This example will be executed by using the shell from the console but it can easily be setup to run as a cron job if you want to automate the process.
The console command to send out an email would be similar to:
cake foo sendTestMail
If everything worked you should have an email going out to the address you specified as the recipient. This example is simple but provides a functional, re-usable, shell task for sending out emails. This example can easily be expanded to send out newsletters or reminders to addresses in a database or incorporated into another shell.
Something that I didn't cover here is the setup of the email templates for use by the Email component. That is well covered in the CakePHP manual so I didn't repeat it here. Just setup the templates as you would for using the Email component is a standard controller.

