• 如果是基于 API 的驱动,需要安装 Guzzle HTTP 库 composer require guzzlehttp/guzzle,不过遗憾的是,好像 Mailgun 驱动、SparkPost 驱动、SES 驱动在国内都不可用,所以我们用 SMTP 服务器形式

  • 一些配置,ENV里面配置,也可以在 config.mail 里面设置

# Laravel自带的SMTP发送邮件
MAIL_DRIVER=smtp		# 驱动
MAIL_HOST=smtp.qq.com	# 邮箱SMTP地址,这个不同厂商地址不同
MAIL_PORT=465	# 端口
MAIL_USERNAME=673996019@qq.com	# 用于发送邮件的邮箱
MAIL_PASSWORD=xxxxxxxxxxx	# 密码,如果是QQ邮箱,就要填写授权密码,163邮箱好像也是授权密码
MAIL_FROM_NAME=舒孝元邮件测试	# 发件人名称
MAIL_FROM_ADDRESS=673996019@qq.com # 默认发送地址,这个还必须和 MAIL_USERNAME 一样,不然会报错
MAIL_ENCRYPTION=ssl		# SSL 协议

直接在控制器里面开撸,在控制器里面引入:use Illuminate\Support\Facades\Mail;,具体可以查看这个类 \vendor\laravel\framework\src\Illuminate\Support\Testing\Fakes\MailFake.php

简单粗暴的演示,直接在控制器里面开撸

发送纯文本邮件、视图模板、上传附件等

<?php
/**
 * Created by PhpStorm.
 * User: xiaoyuan.shu
 * Date: 2019/11/27
 * Time: 13:50
 */

namespace App\Http\Controllers\Test;

use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Mail;

class EmailController extends Controller {
	/**
	 * 发送纯文本邮件
	 */
	public function text() {
		$content = '这个是用 Laravel 的邮件类发送的纯文本邮件,试试看html标签会不会解析:<html><body><h1>舒孝元</h1></body></html>';
		
		// 接收一个文本消息和一个回调函数
		$data = Mail::raw($content, function ($message) {
			$to = env('Admin_EMAIL');
			$message->to($to)->subject('邮件主题:纯文本邮件测试');
		});
		
		// 返回值:null,应该不是这么获取的
//		dd($data);// null
		
		// 这个返回也是个空数组
		dd(Mail::failures());
	}
	
	/**
	 * 通过视图模板发送
	 * 注意,第一个参数为你的视图模板,第二个参数为一个回调函数,里面可以配置一些东西
	 * 如果是视图模板的话,{{ $data }} 会转义html实体标签
	 */
	public function view() {
		$image_url = 'https://i.vgy.me/U3qzgx.png';
		$content = '这个是用 Laravel 的邮件类发送的,主要测试图片+内容';
		$data = Mail::send('emails.shu', [
			'image' => $image_url,
			'data'  => $content
		], function ($message) {
			$to = env('Admin_EMAIL');
			$message->to($to)->subject('邮件主题:测试图片');
		});
		
		//返回值,null
//		dd($data);// null
		
		// 这个返回也是个空数组
		dd(Mail::failures());
	}
	
	/**
	 * 测试上传附件
	 */
	public function enclosure() {
		$image_url = 'https://i.vgy.me/U3qzgx.png';
		$content = '这个是用 Laravel 的邮件类发送的,主要测试附件+图片+内容';
		Mail::send('emails.shu', [
			'image' => $image_url,
			'data'  => $content
		], function ($message) {
			$to = env('Admin_EMAIL');
			$message->to($to)->subject('邮件测试:附件');
			$attachment = '/usr/share/nginx/html/laravel_dev/public/git-webhook_log.txt';
			
			// 在邮件中上传附件
			// 已经实践证明了,这个中文会乱码。
//			$message->attach($attachment, ['as' => 'git拉取日志.txt']);
			
			// 解决乱码
			$message->attach($attachment,['as'=>"=?UTF-8?B?".base64_encode('git拉取日志')."?=.txt"]);
		});
		
		// 这个返回也是个空数组
		dd(Mail::failures());
	}
}

视图模板

<html>
<head>
    <title>测试邮件</title>
</head>
<body>
<h1>这个是H1标签,下面是div里面的信息</h1>
<div>
    {{ $data }}
</div>
<img src="{{ $image }}" alt="test">
</body>
</html>

来点优雅的搞法

生成邮件类

执行 php artisan make:mail WarningMail,在需要的地方调用就行,类路径 app/Mail

<?php

namespace App\Mail;

use App\Models\Wx\WxConfig;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;

class WarningMail extends Mailable {
    use Queueable, SerializesModels;
	
	/**
	 * 可以通过这个公共属性完成数据传递,在视图中可以直接用这个字段
	 * 另外一种就可以直接通过 with 来完成数据传递
	 * @var string
	 */
    public $data;
    /**
     * Create a new message instance.
     *
     * @return void
     */
    public function __construct(WxConfig $config) {
        $this->data = $config;
    }

    /**
     * Build the message.
     * 更多的还是参考我写的那个简单粗暴的类,很多共通之处
     *
     * @return $this
     */
    public function build() {
        return $this
	        // 发件人,如果没这个就采用全局默认的发送地址
	        ->from(env('MAIL_FROM_ADDRESS'))
	        
	        // 视图路径
	        ->view('view.emails.warning')
	        
	        // 附件上传
	        // 解决中文乱码问题
//	    ->attach($attachment,['as'=>"=?UTF-8?B?".base64_encode('git拉取日志')."?=.txt"]);
	        ->attach('/www/error.log',[
		        'as' => 'error.log',
		        
		        // 指定 MIME 类型,其实没必要设置
		        'mime' => 'application/pdf',
	        ]);
        
	        // text 方法接收一个用于渲染邮件内容的模板名,你既可以定义纯文本消息也可以定义 HTML 消息
//	        ->text('emails.orders.shipped_plain');
    }
}

发送邮件

在需要发送邮件的地方 Mail::to($request->user())->send(new WarningMail($config));

在浏览器中先预览邮件

// 预览邮件
Route::any('/mailable', function () {
    $config = App\Models\Wx\WxConfig::find(1);
    
    // 直接在浏览器预览邮件样式
    return new App\Mail\WarningMail($config);
    
    // 在不发送可邮寄类的情况下捕获其 HTML 内容,内容以字符串方式返回
    return (new App\Mail\WarningMail($config))->render();
});

邮件队列

其实没什么好说的,就是在发送邮件的时候入队列,需要提前准备好队列

Mail::to($request->user())
->cc($moreUsers)	// 抄送
->bcc($evenMoreUsers)// 暗抄送
->queue(new WarningMail($config));

事件

Laravel 会在发送邮件消息前触发两个事件

  • MessageSending 事件在消息发送前触发
  • MessageSent 事件在消息发送后触发

需要注意的是这两个事件是在邮件被发送前后触发,而不是推送到队列时,你可以在 EventServiceProvider 中注册对应的事件监听器:

protected $listen = [
    'Illuminate\Mail\Events\MessageSending' => [
        'App\Listeners\LogSendingMessage',
    ],
    'Illuminate\Mail\Events\MessageSent' => [
        'App\Listeners\LogSentMessage',
    ],
];