Friday, August 31, 2018

How to send an email in background with CakePHP?



That's it, how can I send an email in background with CakePHP, preferable using the out-of-the-box Email component?




EDIT: with in background I mean in another thread, or at least allowing the controller method to finish and send the response to the user. I want to run a function, return "OK" to the user and, after that, send an email.



If it's not possible, how could I do it using the PHP mail function? (only if it's a good approach)



Don't know if it matters, but I'm using SMTP.



Thank you in advance.



EDIT 2: I'm trying to use the CakeEmail::deliver() method, as I read from the documentation that:





Sometimes you need a quick way to fire off an email, and you don’t necessarily want do setup a bunch of configuration ahead of time. CakeEmail::deliver() is intended for that purpose.




I'm trying this:



CakeEmail::deliver('myemail@mydomain.com', 'Test', 'Test',
array('from' => 'localhost@localhost.com'), true);



But the mail is not actually being sent. Anyone has any hint on that method?


Answer



So "in the background" means you want to process the mail sending "out of band". This is to give the user a quick response, and to be able to process slow operations like email sending after the user has feedback (or as you say, in a separate thread).



There are a number of ways to achieve this, including:




  • Workers / message queues

  • Cron job




The simplest way is probably to use a cron job that fires off every 15 or 30 seconds.



My recommended approach is to look into workers and queues, and use something like 0mq or RabbitMQ to queue the request to send an email, and process that outside the request.



If you want to do a cron job, rather than sending the email within the request the user has initiated, you would create a new model to represent your outbound email requests, and store that data into your database. Lets call this model Message for example.



CREATE TABLE `messages` (
`id` CHAR(36) NOT NULL PRIMARY KEY,

`to` VARCHAR(255) NOT NULL,
`from` VARCHAR(255) NOT NULL,
`subject` VARCHAR(255) NOT NULL,
`body` TEXT,
`sent` TINYINT(1) NOT NULL DEFAULT 0,
`created` DATETIME
);


Create a Console that grabs the Message model, and does a find for "unsent" messages:




$messages = $this->Message->findAllBySent(0);


Create yourself a send() method to simplify things, and process all unsent messages:



foreach ($messages as $message) {
if ($this->Message->send($message)) {
// Sending was a success, update the database
$this->Message->id = $message['Message']['id'];

$this->Message->saveField('sent', 1, false);
}
}


The implementation of the send() method on the Message model is up to you, but it would just pass the values from the passed in $message and shunt through to CakeEmail (http://api.cakephp.org/class/cake-email)



Once that is done, you can just call the console from the command line (or from your cron).


No comments:

Post a Comment

plot explanation - Why did Peaches' mom hang on the tree? - Movies & TV

In the middle of the movie Ice Age: Continental Drift Peaches' mom asked Peaches to go to sleep. Then, she hung on the tree. This parti...