PHP 发邮件踩坑记:PHPMailer 从入门到避坑

最近做项目要发邮件,什么注册确认、密码重置、订单通知,一堆功能都离不开邮件。PHP 自带的 mail() 函数?说实话,用过的都知道有多坑——配置麻烦、兼容性差、容易被当垃圾邮件。最后还是老老实实用 PHPMailer,踩了一些坑,今天把经验整理一下。

为什么是 PHPMailer

PHPMailer 是 PHP 里最老牌的邮件发送库,功能齐全:

  • 支持 SMTP 认证,TLS/SSL 加密
  • HTML 邮件、附件、嵌入式图片都能搞定
  • 抄送、密送、回复地址这些不在话下

环境要求:PHP 5.5 ~ 8.3,需要开启 mbstringopenssl 扩展。

安装

推荐用 Composer,省心:

1
composer require phpmailer/phpmailer

不想用 Composer 也行,去 GitHub 下载源码,手动引入文件。但都 2026 年了,还是 Composer 吧。

邮箱服务器配置

发邮件得有 SMTP 服务器,常用的 163 和 QQ 邮箱配置如下:

邮箱 SMTP 服务器 SSL 端口
163 smtp.163.com 465 或 994
QQ smtp.qq.com 465 或 587

重要提醒:163、QQ 这些邮箱默认关闭 SMTP 服务,得去邮箱设置里手动开启,然后生成一个「授权码」。后面代码里的密码填的是授权码,不是你的登录密码!

基础用法

直接上代码,能跑的才是好教程:

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
<?php
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;

require 'vendor/autoload.php';

$mail = new PHPMailer(true);

try {
// 服务器配置
$mail->CharSet = "UTF-8";
$mail->isSMTP();
$mail->Host = 'smtp.163.com';
$mail->SMTPAuth = true;
$mail->Username = 'your@163.com'; // 发件邮箱
$mail->Password = '授权码'; // 授权码,不是密码!
$mail->SMTPSecure = 'ssl';
$mail->Port = 465;

// 收发件人
$mail->setFrom('your@163.com', '发件人名字');
$mail->addAddress('receiver@example.com', '收件人名字');

// 邮件内容
$mail->isHTML(true);
$mail->Subject = '邮件标题';
$mail->Body = '<h1>这是 HTML 邮件内容</h1>';

$mail->send();
echo '发送成功';
} catch (Exception $e) {
echo "发送失败: {$mail->ErrorInfo}";
}

发送附件

加附件一行代码的事:

1
2
$mail->addAttachment('/path/to/file.zip');           // 普通附件
$mail->addAttachment('/path/to/image.jpg', '图片.jpg'); // 重命名附件

注意路径要写对,相对路径、绝对路径都行,但要确保文件存在。

嵌入图片到邮件正文

想在邮件正文里显示图片,有两种方式:一种是用 <img src="cid:图片id"> 配合 addEmbeddedImage,另一种是直接 base64 编码嵌入。推荐前者:

1
2
$mail->Body = '<h1>你好</h1><img src="cid:logo">';
$mail->addEmbeddedImage('images/logo.png', 'logo');

常见坑和解决方案

1. SMTP connect failed

最常见的错误。原因可能是:

  • SMTP 服务没开启(去邮箱设置里开)
  • 端口被防火墙拦截(换个端口试试:25、465、587)
  • 服务器地址写错了

2. 认证失败

大概率是密码填错了。163、QQ 邮箱要用授权码,不是登录密码。授权码在邮箱设置里生成。

3. 中文乱码

编码问题,加上这句:

1
$mail->CharSet = "UTF-8";

4. SSL 连接失败

检查 PHP 有没有开启 openssl 扩展,php.ini 里把 extension=openssl 前面的分号去掉,重启服务。

5. 邮件进了垃圾箱

原因很多:发件人和 SMTP 认证邮箱不一致、邮件内容太像广告、域名没有配置 SPF 记录。生产环境建议用专业邮件服务,比如 SendGrid、Mailgun,比自己搭 SMTP 靠谱。

调试技巧

开发阶段遇到问题,打开调试模式:

1
$mail->SMTPDebug = 2;  // 级别 0-4,数字越大越详细

调试完记得关掉,生产环境开调试会暴露敏感信息。

一个完整的例子

把上面的拼起来:

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
<?php
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;

require 'vendor/autoload.php';

$mail = new PHPMailer(true);

try {
$mail->CharSet = "UTF-8";
$mail->SMTPDebug = 0; // 生产环境用 0
$mail->isSMTP();
$mail->Host = 'smtp.163.com';
$mail->SMTPAuth = true;
$mail->Username = 'your@163.com';
$mail->Password = 'your-authorization-code';
$mail->SMTPSecure = 'ssl';
$mail->Port = 465;

$mail->setFrom('your@163.com', 'l1n6yun');
$mail->addAddress('receiver@example.com');
$mail->addReplyTo('your@163.com', 'Reply');

// 附件
$mail->addAttachment('files/report.pdf');

$mail->isHTML(true);
$mail->Subject = '测试邮件';
$mail->Body = '<h2>邮件发送成功!</h2><p>这是一封测试邮件。</p>';
$mail->AltBody = '邮件发送成功!这是一封测试邮件。'; // 纯文本备用

$mail->send();
echo '邮件发送成功';
} catch (Exception $e) {
echo "邮件发送失败: {$mail->ErrorInfo}";
}

PHPMailer 用起来其实不难,主要是 SMTP 配置容易踩坑。记住几个要点:授权码、端口、编码、调试模式,基本就能搞定大部分场景了。

有问题欢迎评论区交流~