EmailComponent in a (cake) Shell
This little Shell Task will allow you to use the EmailComponent from your shell applications like you normally do from WWW.
The problem
How can I use the kickass EmailComponent from my Shell?The solution
EmailTaskThe description
This little Shell Task will allow you to use the EmailComponent from your shell applications like you normally do from WWW.The code should pretty much explain itself. Below is a simple use example:
Demo
Put this code in APP/vendors/shells/my.phpMAKE SURE TO CHANGE THE EMAIL ADDRESSES TO VALID ONES
PHP Snippet:
Download code
<?php
class MyShell extends Shell {
/**
* List of tasks for this shell
*
* @var array
*/
var $tasks = array('Email');
/**
* Email task
*
* @var EmailTask
*/
var $Email;
/**
* Startup method for the shell
*
* Lets set some default params for the EmailTask
*
*/
function startup() {
$this->Email->settings(array(
'from' => 'Me <my@mail.com>',
'template' => 'test'
));
}
/**
* Send just one email
*
*/
function sendMeAnEmail() {
return $this->Email->send(array(
'to' => 'some@mail.com',
'subject' => 'Talking to myself'
));
}
/**
* Send multiple emails, change a few variables on the fly
* and test that we can 'set' variables to the view
*
*/
function sendMyFriendsAnEmail() {
$myFriends = array('fake@mail.com', 'fake@mail.box', 'fake@user.com');
$this->Email->settings(array('subject' => 'Hello friends'));
foreach ($myFriends AS $friend) {
$this->Email->set('someVar', $friend);
$this->Email->send(array(
'to' => $friend,
'subject' => 'Hello ' . $friend
));
}
}
}
?>
Code
Put this code in APP/vendors/shells/tasks/email.phpPHP Snippet:
Download code
<?php
App::import('Core', 'Controller');
App::import('Component', 'Email');
class EmailTask extends Shell {
/**
* Controller class
*
* @var Controller
*/
var $Controller;
/**
* EmailComponent
*
* @var EmailComponent
*/
var $Email;
/**
* List of default variables for EmailComponent
*
* @var array
*/
var $defaults = array(
'to' => null,
'subject' => null,
'charset' => 'UTF-8',
'from' => null,
'sendAs' => 'html',
'template' => null,
'debug' => false,
'additionalParams' => '',
'layout' => 'default'
);
/**
* Startup for the EmailTask
*
*/
function initialize() {
$this->Controller =& new Controller();
$this->Email =& new EmailComponent(null);
$this->Email->startup($this->Controller);
}
/**
* Send an email useing the EmailComponent
*
* @param array $settings
* @return boolean
*/
function send($settings = array()) {
$this->settings($settings);
return $this->Email->send();
}
/**
* Used to set view vars to the Controller so
* that they will be available when the view render
* the template
*
* @param string $name
* @param mixed $data
*/
function set($name, $data) {
$this->Controller->set($name, $data);
}
/**
* Change default variables
* Fancy if you want to send many emails and only want
* to change 'from' or few keys
*
* @param array $settings
*/
function settings($settings = array()) {
$this->Email->_set($this->defaults = array_filter(am($this->defaults, $settings)));
}
}
?>
Watch the magic
Make sure you have created a .ctp file in APP/views/elements/email/html/test.ctpMake sure you have created a .ctp file in
APP/views/layouts/email/html/default.ctp
Go into the CAKE/console directory and execute:
(Windows) cake.bat my sendMyFriendsAnEmail
(Linux) ./cake my sendMyFriendsAnEmail
Thanks to gwoo for feedback and on this little snippet and mariano_iglesias for proofing :)
Comments
Comment
1 A little addition
A nice addition is the Router so that urls in emails will use our custom routes.
To use the router change the second line in the task to:
and addApp::import('Core', array('Router','Controller'));
to the task initialize() methodinclude CONFIGS . 'routes.php';
Question
2 App import replacement
I'm using an old version of Cake 1.2 and can't update to a new version otherwise my app will break in two ;)
Is there a replacement for the two App:import()?
App::import('Core', 'Controller');
App::import('Component', 'Email');
thnx
Comment
3 App import replacement
remove the lines:
// App::import('Core', 'Controller');
// App::import('Component', 'Email');
and change the function initialize to:
function initialize() {
loadComponent('Email');
// $this->Controller =& new Controller();
$this->Email =& new EmailComponent(null);
$this->Email->startup($this->Controller);
}
im using the version "1.2.0.5875 pre-beta"
i hope this help you
Bug
4 Only html emails?
But, can't send text emails.
Trying Email->sendAs ='both', but keep getting 451 error. The same text/html emails send via non-console controllers just fine.
Also, when I throw a 'debug()' into the html email to see what's going on, I get 451s, as well.
Obviously most people use an html-compatible mail client, but still is there some reason this Task can't send text emails or html emails with debug() calls in it?
oh4real
Comment
5 cake 1.2 final changes
function initialize() {
$this->Controller =& new Controller();
$this->Email =& new EmailComponent(null);
$this->Email->initialize($this->Controller);
}
Bug
6 Undefined property: View::$webroot
I have made all as here is written, but got error:
Notice: Undefined property: View::$webroot in ..../cake/libs/view/view.php on line 751
Anybody know how fix it?
Thanks.
Comment
7 Hmm
<?php
class CronShell extends Shell {
function daily() {
App::import('Component', 'Email');
$this->Email =& new EmailComponent(null);
$this->Email->from = 'foo';
$this->Email->to = 'foo';
$this->Email->subject = 'foo';
$this->Email->send('foo');
}
}
Comment
8 the same here...
I'm having the very same problem... I'll try to find it out... Anything I post something in here!
Comment
9 Fixed! Tks Andras!
Just follow Andras' post... you have to change:
LN 44: $this->Email->startup($this->Controller);
To:
LN 44: $this->Email->initialize($this->Controller);
And you are good to go :)
Comment
10 Send Function - Correction
Replace the Send Function with this code.
/**
* Send an email useing the EmailComponent
*
* @param array $settings
* @return boolean
*/
function send($settings = array()) {
$this->settings($settings);
$this->Email->Controller = $this->Controller;
return $this->Email->send();
}
Just a suggestion,
Thanks,
Jaydeep Dave