很多人设计 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
然后 在即时发邮件的代码就能被以下代码取代, 简单的来说就是要发邮件的时候就向数据库这个表里写一行数据.
$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` = 'im@helloacm.com',
`subject` = '$subject',
`content` = '$content',
`ts` = '$ts',
`sent` = 0
";
// 异步要发的邮件
$result = mysql_query($query);
然后 我们需要创建一个 process_email.php 文件用来把还未发送的邮件列表取出来并通过 PHPMailer 发送.
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!
";
// 标记为已经发送
$query = "update `mails` set `sent` = 1 where `id` = $id";
mysql_query($query) or die(mysql_error());
} else {
echo "$sender - failed! $mailer->ErrorInfo
";
}
}
最后 我们需要 del-email.php 用来清理已经发送过的邮件 可以是一天一次.
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
强烈推荐
- 英国代购-畅购英伦
- TopCashBack 返现 (英国购物必备, 积少成多, 我2年来一共得了3000多英镑)
- Quidco 返现 (也是很不错的英国返现网站, 返现率高)
- 注册就送10美元, 免费使用2个月的 DigitalOcean 云主机(性价比超高, 每月只需5美元)
- 注册就送10美元, 免费使用4个月的 Vultr 云主机(性价比超高, 每月只需2.5美元)
- 注册就送10美元, 免费使用2个月的 阿里 云主机(性价比超高, 每月只需4.5美元)
- 注册就送20美元, 免费使用4个月的 Linode 云主机(性价比超高, 每月只需5美元) (折扣码: PodCastInit2022)
- PlusNet 英国光纤(超快, 超划算! 用户名 doctorlai)
- 刷了美国运通信用卡一年得到的积分 换了 485英镑
- 注册就送50英镑 – 英国最便宜最划算的电气提供商
- 能把比特币莱特币变现的银行卡! 不需要手续费就可以把虚拟货币法币兑换
微信公众号: 小赖子的英国生活和资讯 JustYYUK