# 利用 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` ,防止中文亂碼的情況。
如下收到測試郵件,大概是這樣。

## 使用 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 函數
- 無限極分類