利用 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;

/**

* \Mail

*/

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下下来重新跑就没这个问题了。但是邮件似乎还没有发出去。再查!

发表评论:

昵称

邮件地址 (选填)

个人主页 (选填)

php 利用个人邮箱,利用 Composer 完善自己的 PHP 框架(二)——发送邮件相关推荐

  1. 【完结】利用 Composer 完善自己的 PHP 框架(三)——Redis 缓存

    本教程示例代码见 https://github.com/johnlui/My-First-Framework-based-on-Composer 回顾 上两篇文章中我们完成了 View 视图加载类和 ...

  2. php模拟登录qq邮箱_PHP 利用QQ邮箱发送邮件的实现

    这篇文章主要介绍了关于PHP 利用QQ邮箱发送邮件的实现,有着一定的参考价值,现在分享给大家,有需要的朋友可以参考一下在 PHP 应用开发中,往往需要验证用户邮箱.发送消息通知,而使用 PHP 内置的 ...

  3. 2021-01-3 VBA利用企业邮箱自动发送邮件

    VBA利用企业邮箱自动发送邮件 1.应用场景 2.VBA生成PDF附件 3.企业邮箱设置发送账户 4.VBA利用企业邮箱发送邮件 利用Windows任务计划设置定时执行 小结 1.应用场景 所在企业提 ...

  4. 利用qq邮箱作为个人邮件服务器发送邮件

    需求描述 邮件通知很有用处.如何搭建一个邮件服务器,允许发送邮件呢? 实现方法 一.利用开源软件,搭建自己的邮件服务器. 二.利用qq等第三方邮件服务. 自己搭邮件服务器较麻烦,我的需求比较简单,利用 ...

  5. 利用163 邮箱发送邮件

    1.利用163邮箱发送邮件 # _*_ coding:UTF-8 import time import smtplib from email.mime.text import MIMEText fro ...

  6. 内网邮件JAVA535报错_利用网易邮箱发送邮件535报错处理

    相信看到535报错的同学代码编写方面都没有问题,只是不明白为什么填写了帐号密码后还是报535错误,使用网易的126或者163邮箱都会有如此问题. Python报错如下: Traceback (most ...

  7. 如何利用谷歌邮箱别名功能获取无限 Gmail 邮箱

    公众号关注 「奇妙的 Linux 世界」 设为「星标」,每天带你玩转 Linux ! 我们注册有些国外的服务时,是不能用国内邮箱注册的,这时一个 Gmail 邮箱就显得很有必要.而有时候我们会需要注册 ...

  8. 利用外部邮箱发送邮件的方法

    利用外部邮箱发送邮件的方法 bin/mail会默认使用本地sendmail发送邮件,这样要求本地的机器必须安装和启动Sendmail服务,配置非常麻烦,而且会带来不必要的 资源占用.而通过修改配置文件 ...

  9. 如何利用OUTLOOK邮箱提醒你每天上课把课程表导入日历

    新学期开始了,每天上课翻课程表查看自己的课程比较麻烦,就想着怎么能简单快捷的实现在不同终端查看课表的功能(我自己是华为手机加ipad加windows电脑,一直想在这三个终端实现课表同步),在查阅了别人 ...

最新文章

  1. .NET基础示例系列之十六:制做进程监视器
  2. 数据库的默认用户名和默认口令
  3. 给Java新手的一些建议——Java知识点归纳(Java基础部分)
  4. 【正一专栏】爱是一种信仰
  5. Python+selenium 自动化-模拟键盘输入、点击操作,如何查看所支持的全部键位名称
  6. 第二阶段团队项目冲刺第七天
  7. c语言接受socket发送尾部有乱码,C语言socket编程,服务器和一个客户端连接时,服务器能正常收到信息,2个以上就出现BUG了...
  8. 粒子群优化算法Matlab实现(待逐步解释)
  9. excel中$、、^、/、*等各种符号的使用
  10. SAP Marketing Cloud的几大核心模块讲解
  11. 取色器 for Mac
  12. MySQL迁移至MariaDB
  13. 语音转文字的软件APP
  14. 疯狂的快递骗局:你稀里糊涂支付9.9元代收费时,有人已获利几千万!
  15. 【c++】构造函数初始化列表中成员初始化的次序性
  16. 图论算法 最短路程_图论与图学习(二):图算法
  17. Style主题Theme风格Android
  18. servlet3.0理解
  19. matlab 逐日 变逐月,一个逐日系统程序 用SWITCH咋也跳不出循环 求大神指教
  20. 女超人、女强人……究竟是谁在以“女”设限?

热门文章

  1. linux实验总结及心得_安全实验室 | 内网渗透—Linux权限维持技巧总结
  2. python字符串为什么不能修改_为什么在Python(\n)中更改字符串中的行不起作用?...
  3. mysql 禁止使用enum_MySQL慎用 ENUM 字段
  4. C++获取指向二维数组的首元素指针
  5. tensorboard可视化经常出现的两个问题
  6. 【每日SQL打卡】​​​​​​​​​​​​​​​DAY 23丨学生们参加各科测试的次数【难度简单】​
  7. java 改装电动_java 数组
  8. [python]---从java到python(01)---基础与入门上手
  9. 北大暑期课作业 - 对cnblog 和其他技术博客的分析,比较和展望
  10. mysql 事物 锁行 测试_MySQL Transaction--RR事务隔离级别下加锁测试