# 利用 PHPMailer 类实现队里发送邮件
## 邮件发送
首先,到 github 上下载 PHPMailer 类。地址是:https://github.com/PHPMailer/PHPMailer
```
git clone https://github.com/PHPMailer/PHPMailer.git
```
为了方便代码的编写,这里讲代码放入到项目的根目录下。并执行如下代码发送邮件,这里我们分别使用 QQ 邮箱和 Apple 的 iCloud 邮箱进行测试。
```
<?php
// 引入类
$root_path = dirname(__FILE__);
require $root_path . '/PHPMailer/PHPMailerAutoload.php';
// 实例化类
$mail = new PHPMailer;
// 调试模式
//$mail->SMTPDebug = 3; // Enable verbose debug output
$mail->isSMTP(); // Set mailer to use SMTP
$mail->Host = 'smtp.qq.com'; // Specify main and backup SMTP servers
$mail->SMTPAuth = true; // Enable SMTP authentication
$mail->CharSet = 'utf-8'; // 设置邮件内容编码,防止中文乱码
$mail->Username = 'curder@foxmail.com'; // SMTP username
$mail->Password = '**** ****'; // SMTP password
// $mail->SMTPSecure = 'tls'; // Enable TLS encryption, `ssl` also accepted
// $mail->Port = 587; // TCP port to connect to
$mail->setFrom('curder@foxmail.com', 'Curder');
$mail->addAddress('******@icloud.com', '*****'); // 增加一个收件人
// $mail->addAddress('ellen@example.com'); // Name is optional
$mail->addReplyTo('curder@foxmail.com', 'Curder');
// $mail->addCC('cc@example.com'); // 抄送
// $mail->addBCC('bcc@example.com'); // 密送
// $mail->addAttachment('/var/tmp/file.tar.gz'); // Add attachments
// $mail->addAttachment('/tmp/image.jpg', 'new.jpg'); // Optional name
$mail->isHTML(true); // Set email format to HTML
$mail->Subject = '这是邮件主题';
$mail->Body = '<b>这是一封测试邮件</b>';
// $mail->AltBody = 'This is the body in plain text for non-HTML mail clients';
if(!$mail->send()) {
echo 'Message could not be sent.';
echo 'Mailer Error: ' . $mail->ErrorInfo;
} else {
echo 'Message has been sent';
}
```
> 以上代码是从 github 上的简单示例中拷贝得到,并新增了一个属性 `CharSet` ,防止中文乱码的情况。
如下收到测试邮件,大概是这样。
![](https://box.kancloud.cn/bfbc96bb22fa89e379d612ab5b22fd3e_364x166.png)
## 使用 MySQL 队列进行邮件发送
### 为什么需要使用队列?
想象一个实际场景需求:网站管理员需要给全部注册用户发送一个节日祝福的邮件,这里假如网站有 10000+ 的注册用户,理想情况发送没封邮件耗时 0.1 秒,执行一次群发需要多长的时间呢?那么需要:`10000 * 0.1 = 1000 秒`。
此时 1. 假如使用浏览器进行邮件的群发,那么会给用户造成假死的假象,用户体验不好。 2. 假如群发的过程中有发送失败的情况我们无法进行二次发送或者查阅。
为了解决这类问题我们引入队列对问题进行处理。
### 如何使用 MySQL 队列发送邮件
* 首先创建一张代发邮件的表,用于记录要发送的邮箱。
```
create table task_list(
`task_id` int not null auto_increment,
`name` varchar(10) not null default '' comment '用户名',
`email` varchar(30) not null default '' comment '用户邮箱',
`status` tinyint not null default 0 comment '邮件发送状态 -1:待重新发送,0:未发送,1:已发送',
`created_at` int unsigned not null default 0 comment '队列创建时间',
`updated_at` int unsigned not null default 0 comment '队列更新时间',
primary key (task_id)
)engine=innodb charset utf8 comment '队列表';
```
* 使用 PHP + MySQL 轮询,实现队列。代码如下:
```
<?php
$root_path = dirname(__FILE__);
require $root_path . '/PHPMailer/PHPMailerAutoload.php';
function sendMail( $host, $from_email, $from_password, $from_name, $to_email, $to_name, $subject, $content ){
// 实例化类
$mail = new PHPMailer;
// $mail->SMTPDebug = 3;
$mail->isSMTP();
$mail->Host = $host;
$mail->SMTPAuth = true;
$mail->CharSet = 'utf-8';
$mail->Username = $from_email;
$mail->Password = $from_password;
$mail->setFrom($from_email, $from_name);
$mail->addAddress($to_email, $to_name);
$mail->isHTML(true);
$mail->Subject = $subject;
$mail->Body = $content;
if($mail->send()){
return true;
}else{
file_put_contents('fail.txt', $mail->ErrorInfo ."\n",FILE_APPEND);
return false;
}
}
// 连接数据库
try {
$dsn = 'mysql:host=localhost;dbname=test';
$username = 'root';
$password = 'aaaaaa';
$pdo = new PDO($dsn, $username, $password);
$first_start = false;
// 写入一些默认的测试数据,只在第一次运行时开启
if($first_start){
$now_time = time();
$sql = <<<EOF
create table IF NOT EXISTS task_list(
`task_id` int not null auto_increment,
`name` varchar(10) not null default '' comment '用户名',
`email` varchar(30) not null default '' comment '用户邮箱',
`status` tinyint not null default 0 comment '邮件发送状态 -1:待重新发送,0:未发送,1:已发送',
`created_at` int unsigned not null default 0 comment '队列创建时间',
`updated_at` int unsigned not null default 0 comment '队列更新时间',
primary key (task_id)
)engine=innodb charset utf8 comment '队列表';
insert into task_list values (null,'name', '****@icloud.com', 0, $now_time, $now_time),
(null, 'second_name', '******@qq.com', 0, $now_time, $now_time),
(null, 'third_name', '*****@foxmail.com', 0, $now_time, $now_time);
EOF;
$pdo->exec($sql);
}
} catch (PDOException $e) {
echo $e->getMessage();
}
exit;
while ( true ) {
$sql = "SELECT * from task_list WHERE `status` = 0 or `status` = 2 ORDER BY `task_id` ASC LIMIT 0,5;";
$res = $pdo->query($sql); // 查询出五条数据加入队列
if( $res->rowCount() == 0) {
break;
}else{ // 准备发送邮件
foreach( $res as $key => $value ) { // 循环发送邮件
$host = 'smtp-mail.outlook.com';
$from_email = '******@outlook.com';
$from_password = '***************';
$from_name = '*******';
if( sendMail( $host, $from_email, $from_password, $from_name, $value['email'], $value['name'], "PHP + MySQL 模拟队列发送邮件", "这里是测试内容" ) ){
$sql = sprintf('UPDATE task_list SET `status` = 1, updated_at = %d WHERE `task_id` = %d;', time(), $value['task_id'] );
$pdo->exec($sql);
}else{
$sql = sprintf('UPDATE task_list SET `status` = 2, updated_at = %d WHERE `task_id` = %d;', time(), $value['task_id'] );
$pdo->exec($sql);
}
sleep(1); // 休眠 1 秒
}
}
}
```
### 使用 Redis 队列发送邮件
待完成
- 开始
- PHP配置参数的介绍
- PHP代码优化
- php中的命名空间
- PHP文件上传类
- PHP文件下载
- PHP验证码
- ThinkPHP3.2 框架函数
- A函数:实例化控制器
- C函数:设置和获取配置参数
- D函数:实例化模型
- F 函数:快速缓存设置和存取
- M函数:例化模型(无需定义模型类)
- L函数:设置和获取语言变量
- S 函数:缓存设置和存取
- R函数:直接调用控制器的操作方法
- U函数:URL地址生成
- I 函数:安全获取系统输入变量
- 日志
- ThinkPHP在关闭调试模式导致函数被缓存
- MySQL触发器使用时遇到的坑
- PHP常用函数
- 五一回家记录
- window的PHP开发(wamp)下安装redis扩展
- Windows下安装使用Redis
- PHP7新特性
- 利用 phpmailer 类实现队列发送邮件
- GD 库图像处理
- 检测 PHP 模块是否开启
- GD 库操作一般步骤
- GD 库绘画改变字体
- GD 绘制验证码
- GD 缩略图实现
- GD 绘制水印
- 日期时间函数库
- PHP 函数
- 无限极分类