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).
ScenarioMost 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 TableThe 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 ClassDownload
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 scriptThis 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 jobNext 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()' functionTake 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.