..a dose of zero-day know-hows ..

5/17/2009

Using PHPMailer and Crontab in Enqueuing/Sending System Generated Emails

This article covers how to use PHPMailer and Crontab to send Emails via an SMTP server without having to directly trigger the actual email sending task via the web process. This implementation gives a performance gain especially to the systems wherein most actions need to trigger email sending (eg. Notification systems in ERP's, CRM's and CMS's).


Scenario
Most of the systems I have dealt with trigger the sending of Emails from the Web server through the web request. An example of this scenario are Notification Emails being sent to the recipients when a certain action is triggered/accomplished.

Although this is a common approach for most systems eg. CMS, CRM etc., I find it inefficient as the execution speed of the script which sends the actual email is dependent to the SMTP server set to be used, in such events, if the SMTP serves lags/fails on responding, the script which invokes fsckopen will wait until the STMP server answers which might cause the script to timeout after some moments of waiting.

Solution:
Instead of attempting to send the email directly along the web process, it is wise to enqueue the email by storing it on a database, and let crontab pick those entries up and send the emails using the php cli by accessing a PHP Email Class such as PHPMailer. The sent emails in the database can then be flagged as 'sent' so the query which picks the emails up can exclude sent emails via "WHERE `sent` != '1' LIMIT ...".

This is a sample implementation (PHPMailer)

A. Setup the Database Table

The first thing that needs to be done is to create a table where the enqueued emails will be stored. This sample table is generic enough for most purposes, but feel free to expand as deem fit.
CREATE TABLE  `outgoing_emails` (
`id` int(9) NOT NULL auto_increment,
`recepient` text,
`subject` text,
`body` text,
`mode` int(1) default '0',
`date_entered` datetime default NULL,
`sent` int(1) default '0',
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8
In the table above, the basic parts of an Email has columns which correspond to arguments that can be passed to the phpmailer Send() method.

B. Setup the PHPMailer Class
Download PHPMailer (PHPMailer 2.0.4 is used for this example, although other versions may be used), and uncompress it as appropriate.

C. Setup the actual email enqueuing and sending script
This script will be used to access the PHPMailer class, enqueue and send the emails (in short, it will be the all-in-one script which will do all the job). This script will be accessed by cron and execute it via PHP cli.

Note: This is a modified version of the functions used by Mambo CMS to send out emails and is found in all versions up to 4.6.x series. This is a very good implementation anyways and I am lazy to write my own for the sake of demo-ing:



Copy and paste the code above and save as enqueue_emails.php. You may need to modify lines 1-14 to set proper MySQL and SMTP credentials, as well as the path where you extracted the PHPMailer package.

D. Setup the Cron job
Next is set the crontab to run enqueue_emails.php, eg. if you intend to send the email in batches every 2 minutes, you would need to set the cron to the following:

*/2 * * * * php -f /var/www/mail/enqueue_emails.php


E. Reroute the email sending lines in your script to use the 'enqueue_emails()' function
Take it for a spin, An example would be:

require_once( 'enqueue_emails.php' );
enqueue_email('test@example.com', 'email subject', 'email body');

Wait for 2 minutes and let cron pick the email up and send it to the recipient, wait until it arrives in the inbox and And you're done.

For any questions, follow-ups, feel free to leave a comment, I hope this has been helpful.

2 comments:

Unknown said...

Dear Arpee, I am investigating to implement something like this and found your article interesting.

Unluckily, the source code for the enqueue script is no longer available, do you have any copy that you can kindly share?

Thank you and regards,
Hector

Okolie Raymond said...

Hello,

The code for enqueue is not available. Could you pls kindly share as I would like to test out the script and use for a similar project for sending out queued newsletter emails.