PHP实战之发送邮件

#程序员薪资揭榜#你做程序员几年了?月薪多少?发量还在么?>>> PHP实战之发送邮件

1.前言

最近在公司的项目开发中,我又踩坑了,我负责开发公司项目的会员中心,其中涉及到了邮箱验证这个模块,在本地发送邮件接收成功,但是在公司服务器上就发送成功接收失败,百思不得其解,于是我查阅了大量的相关文章,下面把关于PHP发送邮件的知识点再次详细记录一下。

代码分享:https://github.com/mtdgclub/emailPost

sendmail类库,链接:https://pan.baidu.com/s/1FvQDvYgYNte3zdHFLTVLLA ,提取码:tdp4

phpmailer类库,链接:https://pan.baidu.com/s/1YoU0J0xhzZ7nEPi_0Rwp3A ,提取码:dsqb

2.邮件协议

PHP发送邮件的方法和插件挺多的,有PHP的sendmail(内置的 mail() 函数必安装的工具)、PhpMailer、SwiftMailer、ZendMail、Zeatcomponent 的 ezcMailComposer 等等;一般来说,我们需要配置一台邮件服务器,用作发送和接收邮件的中转站。邮件服务器之间常用邮件协议SMTP、POP3、IMAP。

我们通常使用QQ邮箱或者163邮箱的第三方SMTP服务器

PHP实战之发送邮件

这时候就有个思考,不使用第三方服务器,直接发邮件不可以吗?

从技术上来说,是可以的,但不借助任何的网络服务器,那邮件要被暂时存到哪里呢?按照邮件发送的流程,邮件需要有个临时存放的地方,直到接收邮件一方把它取走。如果邮件发送的同时,接收方就进行接收,而没有邮件服务器做中间件的话,那就不叫发邮件,而成了点对点的通信。

真正的邮件方式是离不开邮件服务器的,当然,你也可以把邮件服务器做到本地而不借助其它网络服务器,比如你的本地电脑既实现SMTP、又实现POP3,同时保证接收方未取走邮件之前不要关机,并POP3服务正常工作。但问题是,SMTP实现起来很简单,但要自己实现POP3还是有一定难度的。

既然聊到邮件的协议,我觉得我们也有必要对它们进行了解~

2.1 SMTP

称为简单Mail传输协议(Simple Mail Transfer Protocal),目标是向用户提供高效、可靠的邮件传输。SMTP的一个重要特点是它能够在传送中接力传送邮件,即邮件可以通过不同网络上的主机接力式传送。工作在两种情况下:一是电子邮件从客户机传输到服务器;二是从某一个服务器传输到另一个服务器。SMTP是个请求/响应协议,它监听25号端口,用于接收用户的Mail请求,并与远端Mail服务器建立SMTP连接。

SMTP的缺点:

  • SMTP不能传送可执行文件或其他的二进制对象。
  • SMTP限于传送7位的ASCII码。许多其他非英文国家的文字就无法转换。即使在SMTP网关将EBDCDIC码(即扩充的二/十进制交换码)转换为ASCII码时也会遇到一些麻烦。
  • SMTP服务器会拒绝超过一定长度的邮件。
  • 某些SMTP的实现并没有完全按照smp的标准。

2.2 POP

POP的全称是 Post Office Protocol ,即邮局协议,用于电子邮件的接收,它使用TCP的110端口,现在常用的是第三版,所以简称为POP3。POP3仍采用Client/Server工作模式。当客户机需要服务时,客户端的软件(OutlookExpress或FoxMail)将与POP3服务器建立TCP连接,此后要经过POP3协议的三种工作状态,首先是认证过程,确认客户机提供的用户名和密码,在认证通过后便转入处理状态,在此状态下用户可收取自己的邮件或做邮件的删除,在完成响应的操作后客户机便发出quit命令,此后便进入更新状态,将做删除标记的邮件从服务器端删除掉。到此为止整个POP过程完成。

POP3协议的不足:

POP3天生的缺陷,即当用户接收电子邮件时,所有的信件都从服务器上清除并下载到客户机。在整个收信过程中,用户无法知道邮件的具体信息,只有照单全收入硬盘后,才能慢慢浏览和删除。这使用户几乎没有对邮件接收的控制决定权。一旦碰上邮箱被轰炸,或有比较大的邮件,用户不能通过分析邮件的内容及发信人地址来决定是否下载或删除,从而造成系统资源的浪费。

2.3 IMAP

IMAP是Internet Message AccessProtocol的缩写,它比POP3复杂的多。现在较新的版本是1996年的版本4,即IMAP4【RFC2060】,它目前还只是因特网的建议标准。顾名思义,主要提供的是通过Internet获取信息的一种协议。IMAP像POP那样提供了方便的邮件下载服务,让用户能进行离线阅读,但IMAP能完成的却远远不只这些。IMAP提供的摘要浏览功能可以让你在阅读完所有的邮件到达时间、主题、发件人、大小等信息后才作出是否下载的决定。

IMAP的不足:

在利用服务器磁盘资源方面,IMAP不如POP3。由于使用POP时服务器端的邮件被下载到客户机的同时会删除,因而不占用额外空间用以存放旧的邮件。而IMAP服务器仍然保持旧的邮件,必然占用了额外空间,因此需要定期地删除旧邮件。同时,由于用户查阅信息标题和决定下载哪些附件,也需要一定时间,因此链接时间也比POP方式长。

在应用方面,由于IMAP比较复杂,给开发者开发服务器和客户机的软件带来一些难题。对于ISP来说,采用IMAP意味着要花钱购买相关商业软件,同时会付出高额技术支撑费用,因而商用的实现方案还不多。

2.4 小结

总的来说,目前开发,一般采用SMTP 认证,简单地说就是要求必须在提供了账户名和密码之后才可以登录 SMTP 服务器,这就使得那些垃圾邮件的散播者无可乘之机。终上所述,增加 SMTP 认证的目的是为了使用户避免受到垃圾邮件的侵扰。

3.PHP的mail()函数案例实战

3.1第一步:安装sendmail类库支持

在 Windows 下使用 PHP 内置的 mail() 函数发送邮件,需要先安装sendmail类库支持,下载sendmail.zip链接如下:http://glob.com.au/sendmail/

或者

链接:https://pan.baidu.com/s/1FvQDvYgYNte3zdHFLTVLLA ,提取码:tdp4

下载完成解压后,将其复制到工具类下(我以PHPStudy为例),如下图所示:

PHP实战之发送邮件

3.2第二步:修改php.ini文件配置项

我们以自己的QQ邮箱作为SMTP服务器,具体php.ini设置如下:

[mail function]
SMTP = smtp.qq.com
smtp_port = 465
sendmail_from = [email protected]
sendmail_path ="D:phpStudyPHPTutorialtoolssendmailsendmail.exe -t"

修改完毕后,重启PHP服务器~

3.3第三步:修改sendmail.ini配置

在刚刚解压的文件,打开sendmail.ini配置文件,修改内容如下:

[sendmail]
smtp_server=smtp.qq.com
smtp_port=465
[email protected]
auth_password=zhcipmjvhgmqbbcc
[email protected]
error_logfile=error.log
debug_logfile=debug.log

注意:配置项中的 auth_password 不是邮箱的密码,而是腾讯邮箱的第三方客户端授权码

3.4第四步:使用mail()函数

PHP mail() 函数用于从脚本中发送电子邮件。

语法:

mail(to,subject,message,headers,parameters)
//参数1,必需。规定 email 接收者。
//参数2,必需。规定 email 的主题。
//参数3,必需。定义要发送的消息。
//参数4,可选。规定附加的标题
//参数5,可选。对邮件发送程序规定额外的参数。

3.5第五步:实战测试

<?php
//sendmail.php
$to = "[email protected]";         // 邮件接收者
$subject = "参数邮件";                // 邮件标题
$message = "Hello! 这是邮件的内容。";  // 邮件正文
$from = "[email protected]";   // 邮件发送者
$headers = "From:" . $from;         // 头部信息设置
mail($to,$subject,$message,$headers);
echo "邮件已发送";

接收情况如下:

PHP实战之发送邮件

4.PHPMailer类库案例实战

PHPMailer 是一个封装好的 PHP 邮件发送类,支持发送 HTML 内容的电子邮件,以及可以添加附件发送,并不像 PHP 本身 mail() 函数需要服务器环境支持,您只需要设置邮件服务器以相关信息就能实现邮件发送功能。

4.1第一步:下载PHPMailer类库

官方下载地址如下(需要使用composer):https://github.com/PHPMailer/PHPMailer

如果你的composer失效,可以下载这个旧版本使用:

链接:https://pan.baidu.com/s/1YoU0J0xhzZ7nEPi_0Rwp3A

提取码:dsqb

里面有很多文件,但是目前主要就用到两个文件,如下所示:

  • class.phpmailer.php
  • class.smtp.php

4.2第二步:安装PHP扩展支持

PHPMailer 需要 PHP 的 sockets 扩展支持,而登录 QQ 邮箱 SMTP 服务器则必须通过 SSL 加密,故 PHP 还得包含 openssl 的支持

PS:可以通过 phpinfo() 函数查看 PHP环境是否支持socket 和 openssl 扩展信息

4.3第三步:代码实战

完成上面布置,我们只需建立一个sendmail.php的文件,载入PHPMailer类,并设置相关属性参数,就能正常发送文件~

4.3.1 QQMailer.php类文件

<?php
require_once 'phpmailer/class.phpmailer.php';
require_once 'phpmailer/class.smtp.php';
class QQMailer
{
    public static $HOST = 'smtp.qq.com'; // QQ 邮箱的服务器地址
    public static $PORT = 465; // smtp 服务器的远程服务器端口号
    public static $SMTP = 'ssl'; // 使用 ssl 加密方式登录
    public static $CHARSET = 'UTF-8'; // 设置发送的邮件的编码
    private static $USERNAME = '[email protected]'; // 授权登录的账号
    private static $PASSWORD = 'fangzhijie'; // 授权登录的密码
    private static $NICKNAME = 'FZ杰哥'; // 发件人的昵称

    /**
     * QQMailer constructor.
     * @param bool $debug [调试模式]
     */
    public function __construct($debug = false)
    {
        $this->mailer = new PHPMailer();
        $this->mailer->SMTPDebug = $debug ? 1 : 0;
        $this->mailer->isSMTP(); // 使用 SMTP 方式发送邮件
    }

    /**
     * @return PHPMailer
     */
    public function getMailer()
    {
        return $this->mailer;
    }

    private function loadConfig()
    {
        /* Server Settings  */
        $this->mailer->SMTPAuth = true; // 开启 SMTP 认证
        $this->mailer->Host = self::$HOST; // SMTP 服务器地址
        $this->mailer->Port = self::$PORT; // 远程服务器端口号
        $this->mailer->SMTPSecure = self::$SMTP; // 登录认证方式
        /* Account Settings */
        $this->mailer->Username = self::$USERNAME; // SMTP 登录账号
        $this->mailer->Password = self::$PASSWORD; // SMTP 登录密码
        $this->mailer->From = self::$USERNAME; // 发件人邮箱地址
        $this->mailer->FromName = self::$NICKNAME; // 发件人昵称(任意内容)
        /* Content Setting  */
        $this->mailer->isHTML(true); // 邮件正文是否为 HTML
        $this->mailer->CharSet = self::$CHARSET; // 发送的邮件的编码
    }

    /**
     * Add attachment
     * @param $path [附件路径]
     */
    public function addFile($path)
    {
        $this->mailer->addAttachment($path);
    }

    /**
     * Send Email
     * @param $email [收件人]
     * @param $title [主题]
     * @param $content [正文]
     * @return bool [发送状态]
     */
    public function send($email, $title, $content)
    {
        $this->loadConfig();
        $this->mailer->addAddress($email); // 收件人邮箱
        $this->mailer->Subject = $title; // 邮件主题
        $this->mailer->Body = $content; // 邮件信息
        return (bool)$this->mailer->send(); // 发送邮件
    }
}

4.3.2测试发送邮件sendmailer.php文件

<?php
require_once 'QQMailer.php';
// 实例化 QQMailer
$mailer = new QQMailer(true);
//收件人邮箱
$to_email = '[email protected]';
//邮件标题
$title = '测试标题123';
// 邮件内容
$content = "你好,这是测试内容,我是通过phpmailer发送的邮件";
// 发送QQ邮件
if($mailer->send($to_email, $title, $content))
{
    echo "<script>alert('发送成功');history.back()</script>";die;
}
else
{
    echo "<script>alert('发送失败');history.back()</script>";die;
}
?>

发送结果如下:

PHP实战之发送邮件

4.4第四步:发送附件

<?php
require_once 'phpmailer/class.phpmailer.php'; //载入PHPMailer类
require_once 'phpmailer/class.smtp.php';
$mail = new PHPMailer(); //实例化
$mail->IsSMTP(); // 启用SMTP
$mail->Host = "smtp.qq.com"; //SMTP服务器 以163邮箱为例子
$mail->Port = 465;  //邮件发送端口
$mail->SMTPAuth   = true;  //启用SMTP认证
$mail->SMTPSecure = 'ssl'; // 使用 ssl 加密方式登录
$mail->CharSet  = "UTF-8"; //字符集
$mail->Encoding = "base64"; //编码方式
$mail->Username = "[email protected]";  //你的邮箱
$mail->Password = "zhcipmjvhgmqbbcc";  //你的密码
$mail->Subject = "XX邮件-带附件"; //邮件标题
$mail->From = "[email protected]";  //发件人地址(也就是你的邮箱)
$mail->FromName = "FZ杰哥";  //发件人姓名
$mail->IsHTML(true); //支持html格式内容
$address = "[email protected]";//收件人email
$mail->AddAddress($address, "亲");//添加收件人(地址,昵称)
$mail->AddAttachment('email.xls','add.xls'); // 添加附件,第一个参数是文件路径,第二个参数是指定的名称
//可以上传多个附件,一模一样复制  $mail->AddAttachment(path,name); 代码就行
$mail->AddEmbeddedImage("logo.jpg", "my-attach", "logo.jpg"); //设置邮件中的图片
$mail->Body = '你好, <b>朋友</b>! <br/>这是一封来自<a href="http://mtdg.club" target="_blank">mtdg.club</a>的邮件!<br/><img alt="helloweba" src="cid:my-attach">'; //邮件主体内容
//发送
if(!$mail->Send()) {
echo "Mailer Error: " . $mail->ErrorInfo;
} else {
echo "Message sent!";
}

实例化PHPMailer后,如果你的邮件服务器不需要认证,则设置$mail->SMTPAuth=false,此时不需要密码就可以发送。设置字符集和编码支持中文字符,因为原版的PHPMailer包对中文字符的支持不太理想,所以可以上百度下载改进包。注意附件原名最好不要用中文,可以在AddAttachment()指定中文名称。

发送结果如下:

PHP实战之发送邮件

5.总结

在发送邮件的时候需要注意云服务器发送失败的问题,很多情况在本地可以发送邮件并接收成功,但是在远程测试站发送成功却接收失败,很大程度是服务器配置问题(没有开启相应端口),其中qq对应的smtp服务器是:smtp.qq.com 端口号为465 或587163对应的smtp服务器是:smtp.163.com 端口25;第二,没有配置相应插件或者配置不起作用,如果使用 PHP 内置的 mail() 函数发送邮件,需要安装sendmail类库支持;同样,使用其他类库支持也需要安装相应的类库支持。最后,在生产环境运维是不建议开启25端口,因为这样会使得服务器不安全,这时需要相应配置修改端口;另外,在linux上的配置会有些许差别,具体可以百度。