很多人设计 WEB 应用的时候会需要这么一个给用户 发邮件的功能. 这时候就可以通过 类似 PHPMailer 这种开源的类来即时的发邮件. 这有个不好的地方就是 因为是同步发送方式, 页面在邮件发出去之前 会卡住 而且会造成服务器的负担 可扩展性并不强 (如果一天数以万计的邮件需要发 那么高峰期服务器定不能胜任).
最好的设计方法是后台异步的发邮件, 那么我们首先需要一个SQL表格来存放待发送的邮件:
-- phpMyAdmin SQL Dump -- version 4.2.6 -- http://www.phpmyadmin.net -- -- Host: localhost -- Generation Time: Jul 05, 2015 at 01:24 PM -- Server version: 5.5.40-0ubuntu0.14.04.1 -- PHP Version: 5.5.9-1ubuntu4.5 SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; SET time_zone = "+00:00"; /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; /*!40101 SET NAMES utf8 */; -- -------------------------------------------------------- -- -- Table structure for table `mails` -- CREATE TABLE IF NOT EXISTS `mails` ( `id` bigint(32) unsigned NOT NULL, `sender` varchar(255) NOT NULL, `dest` varchar(255) NOT NULL, `subject` varchar(255) NOT NULL, `content` text NOT NULL, `sent` tinyint(1) NOT NULL, `ts` datetime NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=5 ; -- -- Indexes for dumped tables -- -- -- Indexes for table `mails` -- ALTER TABLE `mails` ADD PRIMARY KEY (`id`), ADD KEY `sent` (`sent`), ADD KEY `ts` (`ts`); -- -- AUTO_INCREMENT for dumped tables -- -- -- AUTO_INCREMENT for table `mails` -- ALTER TABLE `mails` MODIFY `id` bigint(32) unsigned NOT NULL AUTO_INCREMENT,AUTO_INCREMENT=5; /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;

sql-mails-table
然后 在即时发邮件的代码就能被以下代码取代, 简单的来说就是要发邮件的时候就向数据库这个表里写一行数据.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | $ts = date('Y-m-d h:i:s'); $sender = mysql_real_escape_string($_POST['user']); $subject = mysql_real_escape_string($_POST['subject']); $content = mysql_real_escape_string($_POST["content"]); $query = " insert into `mails` set `sender` = '$sender', `dest` = '[email protected]', `subject` = '$subject', `content` = '$content', `ts` = '$ts', `sent` = 0 "; // 异步要发的邮件 $result = mysql_query($query); |
$ts = date('Y-m-d h:i:s'); $sender = mysql_real_escape_string($_POST['user']); $subject = mysql_real_escape_string($_POST['subject']); $content = mysql_real_escape_string($_POST["content"]); $query = " insert into `mails` set `sender` = '$sender', `dest` = '[email protected]', `subject` = '$subject', `content` = '$content', `ts` = '$ts', `sent` = 0 "; // 异步要发的邮件 $result = mysql_query($query);
然后 我们需要创建一个 process_email.php 文件用来把还未发送的邮件列表取出来并通过 PHPMailer 发送.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | set_time_limit(600); $link = mysql_connect("localhost", "user", "password") or die(mysql_error()); mysql_select_db('database') or die(mysql_error()); mysql_query("SET NAMES 'utf8'"); mysql_query("SET CHARACTER SET utf8"); mysql_set_charset("utf-8", $link); // 获得即将要发送的邮件列表 limit 100 设置每次处理 100封邮件 可以去掉或者改其它数字 $query = "select * from `mails` where `sent` = 0 limit 100"; $result = mysql_query($query) or die(mysql_error()); require("PHPMailerAutoload.php"); $mailer = new PHPMailer(); $mailer->CharSet = "UTF-8"; $mailer->IsHTML(true); // 一封一封的发 while ($row = mysql_fetch_array($result)) { $sender = $row['sender']; $dest = $row['dest']; $subject = $row['subject']; $content = $row['content']; $id = $row['id']; $mailer->From = $sender; $mailer->FromName = $sender; $mailer->ClearAllRecipients(); $mailer->AddAddress($dest, $dest); $mailer->Subject = $subject; $mailer->Body = $content; if ($mailer->Send()) { echo "$sender - OK! <br />"; // 标记为已经发送 $query = "update `mails` set `sent` = 1 where `id` = $id"; mysql_query($query) or die(mysql_error()); } else { echo "$sender - failed! $mailer->ErrorInfo <br />"; } } |
set_time_limit(600); $link = mysql_connect("localhost", "user", "password") or die(mysql_error()); mysql_select_db('database') or die(mysql_error()); mysql_query("SET NAMES 'utf8'"); mysql_query("SET CHARACTER SET utf8"); mysql_set_charset("utf-8", $link); // 获得即将要发送的邮件列表 limit 100 设置每次处理 100封邮件 可以去掉或者改其它数字 $query = "select * from `mails` where `sent` = 0 limit 100"; $result = mysql_query($query) or die(mysql_error()); require("PHPMailerAutoload.php"); $mailer = new PHPMailer(); $mailer->CharSet = "UTF-8"; $mailer->IsHTML(true); // 一封一封的发 while ($row = mysql_fetch_array($result)) { $sender = $row['sender']; $dest = $row['dest']; $subject = $row['subject']; $content = $row['content']; $id = $row['id']; $mailer->From = $sender; $mailer->FromName = $sender; $mailer->ClearAllRecipients(); $mailer->AddAddress($dest, $dest); $mailer->Subject = $subject; $mailer->Body = $content; if ($mailer->Send()) { echo "$sender - OK! <br />"; // 标记为已经发送 $query = "update `mails` set `sent` = 1 where `id` = $id"; mysql_query($query) or die(mysql_error()); } else { echo "$sender - failed! $mailer->ErrorInfo <br />"; } }
最后 我们需要 del-email.php 用来清理已经发送过的邮件 可以是一天一次.
1 2 3 4 5 6 7 8 9 10 11 12 | set_time_limit(600); mysql_connect("localhost", "user", "password") or die(mysql_error()); function run_query($query) { echo $query; mysql_query($query) or die(mysql_error()); echo " ***OK!*** \n"; } mysql_select_db('database') or die(mysql_error()); $query = 'delete from `mails` where `sent` = 1'; run_query($query); |
set_time_limit(600); mysql_connect("localhost", "user", "password") or die(mysql_error()); function run_query($query) { echo $query; mysql_query($query) or die(mysql_error()); echo " ***OK!*** \n"; } mysql_select_db('database') or die(mysql_error()); $query = 'delete from `mails` where `sent` = 1'; run_query($query);
然后我们就可以通过 crontab -e 加入两个任务, 比如一个一分钟检查邮件列表并发送 另一个一天检查一次清理已经发送的邮件, 这样的话服务器可扩展性就大大增强 (可以避免短时间大量邮件的发送)
异步Asynchronous最重要的就是引入中间件, 没有什么不是一个中间件(如消息队列)不能解决的问题, 如果有, 那就用两个. 这里的中间件就是数据库, 要发邮件时候把邮件写到数据库里, 然后通过另一个程序/脚本定时从数据库里读取邮件再一个一个发送.
英文: Send Emails using Crontab for Your Web Applications
GD Star Rating
loading...
本文一共 539 个汉字, 你数一下对不对.loading...
上一篇: 在英国请专门装修公司铺地板
下一篇: BASH 脚本 防止 iptablex 攻击
扫描二维码,分享本文到微信朋友圈

学习了.回头试试.