一、phpmailer下载
https://packagist.org/packages/phpmailer/phpmailer
composer require phpmailer/phpmailer


安装完成后,项目vendor目录下会生成phpmailer/phpmailer文件夹,同时 Composer 会自动加载类库,无需手动引入文件,直接在代码中使用命名空间即可。
二、封装通用邮件发送类
在application\common\lib\目录下封装邮件工具类(自动加载、全局可用)包含基础配置、核心发送方法、支持自定义收件人、主题、内容附件等。
创建工具类:
application/common/lib/Email.php
<?php
namespace app\common\lib;
// 引入PHPMailer核心命名空间(Composer自动加载,无需手动require)
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\SMTP;
use PHPMailer\PHPMailer\Exception;
/**
* ThinkPHP5.1 PHPMailer邮件发送工具类
* 支持:SMTP加密、多收件人、HTML内容、附件发送、抄送/密送
*/
class Email
{
// 邮件发送核心方法
public static function send($to, $subject, $content, $attach = [], $cc = [], $bcc = [])
{
// 1. 初始化PHPMailer实例,true表示开启异常处理(推荐)
$mail = new PHPMailer(true);
try {
// 2. 服务器配置(关键!根据自己的邮箱SMTP信息修改)
$mail->SMTPDebug = SMTP::DEBUG_OFF; // 调试模式:OFF=关闭(生产环境)、SERVER=服务器信息、CLIENT=客户端信息
$mail->isSMTP(); // 使用SMTP协议发送
$mail->Host = 'smtp.qq.com'; // 邮箱SMTP服务器地址(例:163邮箱=smtp.163.com,QQ邮箱=smtp.qq.com)
$mail->SMTPAuth = true; // 开启SMTP身份验证
$mail->Username = '2065646680@qq.com'; // 发件人邮箱账号
$mail->Password = 'urikxzrimckwcecb'; // 发件人邮箱授权码(不是登录密码!重要!)
$mail->SMTPSecure = 'ssl'; // 加密方式:SSL(常用)/TLS,根据邮箱要求选择
$mail->Port = 465; // 对应加密方式的端口:SSL=465,TLS=587(需与SMTPSecure匹配)
// 3. 发件人信息
$mail->setFrom('2065646680@qq.com', '主邮件'); // 发件人邮箱(与Username一致)、发件人昵称(自定义,如“XX系统”)
$mail->CharSet = 'UTF-8'; // 设置邮件编码,解决中文乱码(必须!)
// 4. 收件人配置(支持单个/多个收件人)
if (is_string($to)) {
$to = explode(',', $to); // 单个收件人直接转数组,多收件人用逗号分隔(例:a@163.com,b@qq.com)
}
foreach ($to as $email) {
$mail->addAddress(trim($email)); // 添加收件人,trim()去除空格避免错误
}
// 5. 抄送/密送(可选,按需启用)
if (!empty($cc)) {
$cc = is_string($cc) ? explode(',', $cc) : $cc;
foreach ($cc as $email) {
$mail->addCC(trim($email)); // 抄送
}
}
if (!empty($bcc)) {
$bcc = is_string($bcc) ? explode(',', $bcc) : $bcc;
foreach ($bcc as $email) {
$mail->addBCC(trim($email)); // 密送
}
}
// 6. 附件配置(可选,支持单个/多个附件)
if (!empty($attach)) {
$attach = is_string($attach) ? [$attach] : $attach;
foreach ($attach as $filePath) {
// 验证附件文件是否存在且可读
if (is_file($filePath) && is_readable($filePath)) {
$mail->addAttachment($filePath); // 添加附件(可传第二个参数自定义附件名称)
} else {
throw new \Exception("附件不存在或不可读:{$filePath}");
}
}
}
// 7. 邮件内容配置
$mail->isHTML(true); // 设置邮件内容为HTML格式(支持富文本、图片等),false为纯文本
$mail->Subject = $subject; // 邮件主题
$mail->Body = $content; // HTML邮件内容
$mail->AltBody = strip_tags($content); // 纯文本备用内容(当收件人邮箱不支持HTML时显示)
// 8. 执行发送
$mail->send();
return [
'code' => 1,
'msg' => '邮件发送成功'
];
} catch (Exception $e) {
// 捕获PHPMailer自身异常(邮件发送相关错误)
return [
'code' => 0,
'msg' => 'PHPMailer错误:' . $mail->ErrorInfo // ErrorInfo是PHPMailer内置的错误信息方法
];
} catch (\Exception $e) {
// 捕获自定义异常/其他全局异常(如附件不存在)
return [
'code' => 0,
'msg' => '系统错误:' . $e->getMessage()
];
}
}
}常见邮箱服务器:

授权码不是登录密码!
所有主流邮箱(163/QQ/ 新浪等)为了安全,禁止直接使用登录密码进行 SMTP 验证,必须先开启「SMTP 服务」并获取「授权码」,步骤如下(通用流程):
登录发件人邮箱,进入「设置」→「POP3/SMTP/IMAP」;
开启「SMTP 服务」(部分邮箱需开启 POP3);
验证身份(手机短信 / 密保),获取授权码;
将代码中的Password值改为该授权码(不是邮箱登录密码!)。
三、场景使用
在Index.php控制器中
(单人收件+纯文本)
<?php
namespace app\index\controller;
use think\Controller;
use app\common\lib\Email; // 引入邮件工具类
class Index extends Controller
{
public function sendEmail()
{
$to = 'm18328321035@163.com '; // 收件人邮箱
$subject = 'ThinkPHP5.1 PHPMailer测试邮件'; // 邮件主题
$content = '这是一封由ThinkPHP5.1集成PHPMailer发送的纯文本测试邮件,请注意查收!'; // 纯文本内容
// 调用发送方法
$result = Email::send($to, $subject, $content);
if ($result['code'] == 1) {
return json($result); // 返回成功
} else {
return json($result, 400); // 返回失败,状态码400
}
}
}多人收件+富文本
public function sendHtmlEmail()
{
$to = 'a@163.com,b@qq.com,c@sina.com'; // 多收件人,逗号分隔
$subject = '【XX系统】您的账号登录提醒';
// HTML富文本内容(支持CSS、图片、链接)
$content = <<<HTML
<div style="width: 600px; margin: 0 auto; padding: 20px; border: 1px solid #eee;">
<h3 style="color: #333;">账号登录提醒</h3>
<p>尊敬的用户,您好!</p>
<p>您的账号于 <span style="color: red; font-weight: bold;">2026-02-02 15:30</span> 在异地登录,若非本人操作,请及时修改密码:<a href="https://xxx.com/reset">点击修改</a></p>
<p style="color: #999; margin-top: 30px;">此邮件为系统自动发送,请勿回复!</p>
</div>
HTML;
$result = Email::send($to, $subject, $content);
dump($result); // TP5.1内置dump方法,打印结果
}带附件发送邮件
public function sendAttachEmail()
{
$to = 'recipient@163.com';
$subject = '【XX系统】您的月度报表已发送';
$content = '您好!您的2026年1月月度报表已作为附件发送,请查收!';
// 附件配置:支持单个(字符串)/多个(数组),使用TP5.1框架常量拼接绝对路径
$attach = [
ROOT_PATH . 'public' . DS . 'file' . DS . '202601报表.xlsx', // 报表文件
ROOT_PATH . 'runtime' . DS . 'export' . DS . '202601数据.pdf' // 数据文件
];
// 单个附件直接传字符串:$attach = ROOT_PATH . 'public/file/202601报表.xlsx';
$result = Email::send($to, $subject, $content, $attach);
dump($result);
}带抄送、密送 + html + 附件
public function sendFullEmail()
{
$to = 'main@qq.com'; // 主收件人
$cc = 'cc1@163.com,cc2@sina.com'; // 抄送(多地址逗号分隔)
$bcc = ['bcc1@qq.com', 'bcc2@163.com']; // 密送(数组格式)
$subject = '【项目会议】会议纪要及资料';
$content = '<h3>项目会议纪要</h3><p>本次会议讨论内容如下:...</p>';
$attach = ROOT_PATH . 'public/file/会议纪要.docx'; // 单个附件
// 调用时传入抄送、密送参数
$result = Email::send($to, $subject, $content, $attach, $cc, $bcc);
dump($result);
}四、生产环境下配置
application/common/config/email.php
<?php return [ 'host' => 'smtp.163.com', 'username' => 'your_email@163.com', 'password' => 'your_auth_code', 'smtp_secure'=> 'SSL', 'port' => 465, 'from_email' => 'your_email@163.com', 'from_name' => 'XX系统' ];
修改工具类下的配置信息:
// 替换原硬编码配置
$config = config('email'); // 读取配置文件
$mail->Host = $config['host'];
$mail->Username = $config['username'];
$mail->Password = $config['password'];
$mail->SMTPSecure = $config['smtp_secure'];
$mail->Port = $config['port'];
$mail->setFrom($config['from_email'], $config['from_name']);异步发送(解决邮件发送阻塞请求)
public function sendEmail()
{
// 先返回成功结果,断开前端连接
fastcgi_finish_request();
// 后续执行邮件发送,不阻塞前端
$to = 'recipient@qq.com';
$subject = '异步测试邮件';
$content = '这是一封异步发送的邮件';
Email::send($to, $subject, $content);
}工具类调用:
Email::send($to, $subject, $content, $attach = [], $cc = [], $bcc = [])
