企业🤖AI智能体构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
# 利用 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 队列发送邮件 待完成