利用 Composer 完善自己的 PHP 框架(二)——发送邮件
2014-10-18 / 阅读数:23506 / 分类: PHP
回顾
上一篇文章中,我们手工建造了一个简易的视图加载器,顺便引入了错误处理包,让我们的 MFFC 框架在 M、V、C 三个方面都达到了“好用”的水平。View 是一个可插拔组件,在本篇文章中我们要创建另一个可插拔组件——邮件发送模块。
正文
我们采用 'nette/mail' 包作为我们的邮件发送基础模块,在它的基础上封装一个 'Mail' 类,暴露出简洁的 API 给控制器使用,下面我们正式开始。
引入 'nette/mail' 包,修改 'composer.json':"require": {
"codingbean/macaw": "dev-master",
"illuminate/database": "*",
"filp/whoops": "*",
"nette/mail": "*"
},
运行 'composer update',等待安装完成。'nette/mail' 的文档位于:http://doc.nette.org/en/2.2/mailing 让我们阅读它,然后设计 Mail 类:
新建 'services/Mail.php' 文件,内容如下:<?php
use Nette\Mail\Message;
/**
*/
class Mail extends Message
{
public $config;
// [String] e-mail
protected $from;
// [Array] e-mail list
protected $to;
protected $title;
protected $body;
function __construct($to)
{
$this->config = require BASE_PATH.'/config/mail.php';
$this->setFrom($this->config['username']);
if ( is_array($to) ) {
foreach ($to as $email) {
$this->addTo($email);
}
} else {
$this->addTo($to);
}
}
public function from($from=null)
{
if ( !$from ) {
throw new InvalidArgumentException("邮件发送地址不能为空!");
}
$this->setFrom($from);
return $this;
}
public static function to($to=null)
{
if ( !$to ) {
throw new InvalidArgumentException("邮件接收地址不能为空!");
}
return new Mail($to);
}
public function title($title=null)
{
if ( !$title ) {
throw new InvalidArgumentException("邮件标题不能为空!");
}
$this->setSubject($title);
return $this;
}
public function content($content=null)
{
if ( !$content ) {
throw new InvalidArgumentException("邮件内容不能为空!");
}
$this->setHTMLBody($content);
return $this;
}
}
Mail 类和 View 类工作的方式基本一致:$this->mail = Mail::to(['ooxx@gmail.com', 'ooxx@qq.com'])
->from('MotherFucker ')
->title('Fuck Me!')
->content('
Hello~~
');上面这段代码位于 HomeController 中, 'View::make()' 那行代码的下面。
新建 'MFFC/config/mail.php',请自行替换邮件地址和密码:<?php
return [
'host' => 'smtp.163.com',
'username' => 'ooxx@163.com',
'password' => 'password',
'secure' => ''
];
Mail 和 View 一样也在 BaseController 的析构函数 __destruct() 函数中处理,现在这个 function 长这样:public function __destruct()
{
$view = $this->view;
if ( $view instanceof View ) {
extract($view->data);
require $view->view;
}
$mail = $this->mail;
if ( $mail instanceof Mail ) {
$mailer = new Nette\Mail\SmtpMailer($mail->config);
$mailer->send($mail);
}
}
OK,准备的差不多了,运行 'composer dump-autoload' 把 Mail 类加入自动加载,刷新页面!
如果你看到以上页面,恭喜你!邮件发送成功了!
赶快去检查一下收件箱有木有邮件!:-D 这次页面加载可能会稍慢,因为邮件是同步发送的。异步的队列系统我们会在以后讲到。
分析
邮件发送的整体流程想必大家已经轻车熟路了,现在主要叙述一下 Mail 类的设计过程:邮件发送的核心参数是 '目标地址',即邮件要发送到的 E-mail 地址,所以我们设计 Mail::to('oo@xx.me') 作为发送的 '触发 API'。
目前我们采用最简单的 'SMTP' 方式发送邮件,文档在 这里。配置文件放置在 'MFFC/config/mail.php' 中,依旧返回一个数组。
Mail 类继承了 'Nette\Mail\Message' 类。'Mail::to()' 的时候创建一个 Mail 类的实例(对象)并返回,这时候其实 'BaseController' 中的析构函数中的代码已经会被触发并处理这个对象了。默认的发送人是从配置文件中读取的 'username'。
'Mail::to()' 支持 字符串 或者数组作为参数,可以一次发送一封或多封邮件。
'from()'、'title()' 和 'content()' 方法用于丰富邮件内容。'content()' 方法可以直接传递 HTML 代码。
'from()' 配置不一定都能够成功,部分邮件服务商不支持修改发送人地址。
这个变量全部组装完成后,被赋值给控制器的 '$mail' 成员变量,然后被析构函数处理,邮件被发送,成功后页面代码被发送回客户端,流程结束。
WRITTEN BY
程序员,Swift Contributor,正在写《iOS 可视化编程与 Auto Layout》。
评论:
lhh
2018-03-02 14:10
phpstorm 点进去能找到mail类,但是报错是Class 'Services\Mail' not found
daode
2020-08-25 18:31
@lhh:composer dump-autoload 试试
小样
2018-01-31 15:37
按照配置配置完成mail服务之后,报错
SMTP server did not accept . with error: 554 DT:SPM 163 smtp2,DNGowACnMfatcXFaOgQVAA--.297S2 1517384109,please see http://mail.163.com/help/help_spam_16.htm?ip=61.149.143.14&hostid=smtp2&time=1517384109
请问博主,这是啥情况呢?是配置项没有配对还是程序验证上哪里出问题了呢
jason
2017-07-10 16:43
我想请教大佬@JohnLui,到目前为止,View或者Mail这类功能再析构中触发是基于性能考虑,或者是什么考虑?
2017-07-10 16:49
@jason:我把 TinyView 放到析构中触发是为了不侵入主流程。。。
至于 Mail,这东西比较耗时,实际场景下一般使用队列系统,异步发送。
haha
2017-06-06 19:25
config/mail.php 由163换车搜狐的邮箱就可以了,163的邮箱安全验证比较严格导致
return [
'host' => 'smtp.sohu.com',
'username' => 'xxxxx@sohu.com',
'password' => 'xxxxx',
'secure' => ''
];
kun
2017-04-05 19:44
我的也没有报错,效果也和博主的一样,可为什么没有收到呢 ,应该还是发送不成功。
crlt_
2018-01-17 10:34
@kun:可以看看你的垃圾箱
风无心
2016-08-18 18:22
markdown写出来的文档,直接让人有种跪舔的冲动
woodstig3
2015-08-21 21:48
按照教主的示例做下来,总是返回:“No connection could be made because the target machine actively refused it.”这好像是SMTP服务器的设置问题,但是查看了163的邮箱设置,确实打开了SMTP服务了,为什么无法连接上呢?
woodstig3
2015-08-23 15:25
@woodstig3:问题没有找到,但是从教主的github主页上把Mail.php下下来重新跑就没这个问题了。但是邮件似乎还没有发出去。再查!
发表评论:
昵称
邮件地址 (选填)
个人主页 (选填)