很多人设计 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 */;
然后 在即时发邮件的代码就能被以下代码取代, 简单的来说就是要发邮件的时候就向数据库这个表里写一行数据.
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` = 'im@helloacm.com', `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` = 'im@helloacm.com', `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 加入两个任务 比如一个一分钟检查邮件列表并发送 另一个一天检查一次清理已经发送的邮件 这样的话服务器可扩展性就大大增强 (可以避免短时间大量邮件的发送)
英文: https://helloacm.com/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