发送邮件(运用Laravel的邮件、队列、任务调度、Redis等服务)
本文总结运用Laravel的邮件、队列、任务调度、Redis等服务来完成定时给新注册的邮件用户发送邮件的功能(附上编写适配性好的邮件页面的方法)。
我们通过制定计划任务来定时执行自定的Artisan命令,在命令中去执行发送邮件的业务逻辑代码(我们将发送邮件的方法写在队列文件中来调用)。
共分为五步来实现:
第一步:配置邮件服务
第二步:配置队列服务
第三步:配置计划任务,自定义Artisan命令
第四步:编写业务代码
第五步:调试邮件适配
第一步:配置邮件服务
Laravel服务-邮件说明文档
实际应用:
简介
Laravel基于目前流行的SwiftMailer库提供了一套干净清爽的邮件API。Laravel为
SMTP、Mailgun、Mandrill、Amazon SES、PHP的mail函数,以及sendmail提供了驱动,从而允许你快速通过本地或云服务发送邮件。
基于驱动的API如Mailgun和Mandrill通常比SMTP服务器更简单、更快。所有的API驱动要求应用已经安装Guzzle HTTP库。你可以通过添加如下行到
composer.json文件来安装Guzzle到项目:
"guzzlehttp/guzzle": "~5.3|~6.0"
我们这里使用smtp,.env文件配置如下:
MAIL_DRIVER=smtp MAIL_HOST= MAIL_PORT= MAIL_USERNAME= MAIL_PASSWORD= MAIL_ENCRYPTION=ssl MAIL_FROM_ADDRESS= MAIL_FROM_NAME=
发送邮件
Laravel允许你在视图中存储邮件信息,例如,要组织你的电子邮件,可以在
resources/views目录下创建
emails目录。
要发送一条信息,使用
Mail门面上的send方法。send方法接收三个参数。第一个参数是包含邮件信息的视图名称;第二个参数是你想要传递到该视图的数组数据;第三个参数是接收消息实例的闭包回调——允许你自定义收件人、主题以及邮件其他方面的信息,我们在
app/Jobs/SendMail.php队列中写发送邮件代码:
(配置队列见下一步)
<?php namespace App\Jobs; use Illuminate\Queue\SerializesModels; use Illuminate\Contracts\Bus\SelfHandling; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Support\Facades\Mail; class SendMail extends Job implements SelfHandling, ShouldQueue { use SerializesModels; protected $username; protected $email; protected $subject; protected $viewTemplate; protected $data; protected $fromAddress; protected $fromName; public function __construct($username, $email, $subject, $viewTemplate, $data = [], $fromAddress = null, $fromName = null) { $this->username = $username; $this->email = $email; $this->subject = $subject; $this->viewTemplate = $viewTemplate; $this->data = $data; $this->fromAddress = $fromAddress; $this->fromName = $fromName; } public function handle() { // 首先在handle的时候,会让job尝试3次,失败后被扔回queue,再重置执行 for ($i = 0; $i < 3; ++$i) { if ($this->sendMail()) { return true; } } return true; //throw new \Exception('send mail failed'); } protected function sendMail() { $username = $this->username; $email = $this->email; $subject = $this->subject; $fromAddress = is_null($this->fromAddress) ? env('MAIL_FROM_ADDRESS') : $this->fromAddress; $fromName = is_null($this->fromName) ? env('MAIL_FROM_NAME') : $this->fromName; $status = Mail::send($this->viewTemplate, $this->data, function ($message) use ($email, $username, $subject, $fromAddress, $fromName) { $message->from($fromAddress, $fromName)->to($email, $username)->subject($subject); }); return $status; } }
构造消息
传递给send方法的第三个参数是一个允许你指定邮件消息本身多个选项的闭包。使用这个闭包可以指定消息的其他属性,例如抄送、群发,等等:
$message->from($address, $name = null); $message->sender($address, $name = null); $message->to($address, $name = null); $message->cc($address, $name = null); $message->bcc($address, $name = null); $message->replyTo($address, $name = null); $message->subject($subject); $message->priority($level); $message->attach($pathToFile, array $options = []); // 从$data字符串追加文件... $message->attachData($data, $name, array $options = []); // 获取底层SwiftMailer消息实例... $message->getSwiftMessage();
第二步:配置队列服务
Laravel服务-队列说明文档
实际应用:
简介
Laravel队列服务为各种不同的后台队列提供了统一的API。队列允许你推迟耗时任务(例如发送邮件)的执行,从而大幅提高web请求速度。
配置
队列配置文件存放在
config/queue.php。在该文件中你将会找到框架自带的每一个队列驱动的连接配置,包括
数据库、Beanstalkd、 IronMQ、 Amazon SQS、 Redis以及同步(本地使用)驱动。其中还包含了一个null队列驱动以拒绝队列任务。
队列依赖
* database:为了使用database队列驱动,需要一张数据库表来存放任务,要生成创建该表的迁移,运行Artisan命令queue:table,迁移被创建好了之后,使用migrate命令运行迁移:
php artisan queue:table php artisan migrate
- Amazon SQS: aws/aws-sdk-php ~3.0
- Beanstalkd: pda/pheanstalk ~3.0
- IronMQ: iron-io/iron_mq ~2.0
- Redis: predis/predis ~1.0
我们这里使用同步,在.env中配置
QUEUE_DRIVER=sync
编写任务类
1)生成任务类
默认情况下,应用的所有队列任务都存放在
app/Jobs目录。你可以使用Artisan CLI生成新的队列任务:
php artisan make:job SendMail --queued
该命令将会在app/Jobs目录下生成一个新的类,并且该类实现了Illuminate\Contracts\Queue\ShouldQueue接口,告诉Laravel该任务应该被推送到队列而不是同步运行。
2) 任务类结构
任务类非常简单,正常情况下只包含一个当队列处理该任务时被执行的handle方法,我们将发送邮件直接写在handle里,实例代码见上一步中的发送邮件部分。
handle方法在任务被队列处理的时候被调用,注意我们可以在任务的handle方法中对依赖进行类型提示。Laravel服务容器会自动注入这些依赖。
推送任务到队列
默认的Laravel控制器位于
app/Http/Controllers/Controller.php并使用了
DispatchesJobs trait。
该trait提供了一些允许你方便推送任务到队列的方法,例如dispatch方法(在控制器中):
<?php namespace App\Http\Controllers; use App\User; use Illuminate\Http\Request; use App\Jobs\SendReminderEmail; use App\Http\Controllers\Controller; class UserController extends Controller{ /** * 发送提醒邮件到指定用户 * * @param Request $request * @param int $id * @return Response */ public function sendReminderEmail(Request $request, $id) { $user = User::findOrFail($id); $this->dispatch(new SendReminderEmail($user)); } }
当然,有时候你想要从应用中路由或控制器之外的某些地方分发任务,因为这个原因,你可以在应用的任何类中包含DispatchesJobs trait,从而获取对分发方法的访问,举个例子,下面是使用该trait的示例类:
<?php namespace App; use Illuminate\Foundation\Bus\DispatchesJobs; class ExampleClass{ use DispatchesJobs; }
为任务指定队列
你还可以指定任务被发送到的队列。
通过推送任务到不同队列,你可以对队列任务进行“分类”,甚至优先考虑分配给多个队列的worker数目。这并不会如队列配置文件中定义的那样将任务推送到不同队列“连接”,而只是在单个连接中发送给特定队列。
要指定该队列,使用任务实例上的onQueue方法,该方法有Laravel自带的基类App\Jobs\Job提供:
<?php namespace App\Http\Controllers; use App\User; use Illuminate\Http\Request; use App\Jobs\SendReminderEmail; use App\Http\Controllers\Controller; class UserController extends Controller{ /** * 发送提醒邮件到指定用户 * * @param Request $request * @param int $id * @return Response */ public function sendReminderEmail(Request $request, $id) { $user = User::findOrFail($id); $job = (new SendReminderEmail($user))->onQueue('emails'); $this->dispatch($job); } }
实例代码见第四步
第三步:配置计划任务,自定义Artisan命令
我们通过设置计划任务来定时调用自定义的Artisan命令,命令里执行发送邮件的逻辑,来实现定时发送邮件。
Laravel服务-任务调度说明文档
Laravel自定义Artisan命令说明文档
实际应用:
任务调度简介
在以前,开发者需要为每一个需要调度的任务编写一个Cron条目,这是很让人头疼的事。你的任务调度不在源码控制中,你必须使用SSH登录到服务器然后添加这些Cron条目。Laravel命令调度器允许你平滑而又富有表现力地在Laravel中定义命令调度,并且服务器上只需要一个Cron条目即可。
任务调度定义在app/Console/Kernel.php文件的schedule方法中,该方法中已经包含了一个示例。你可以自由地添加你需要的调度任务到Schedule对象。
1)在服务器上开启调度
在服务的/var/spool/cron/root文件中添加代码,
在命令行输入:
crontab -e
添加如下代码:
* * * * * php路径 项目路径/artisan schedule:run >> /dev/null 2>&1
在命令行输入:
crontab -u root -l查看
不需要重启cron服务,因为系统每分钟都会读一遍/var/spool/cron目录下的文件
如果发现按照如下配置还是不能执行的话,可以用以下方法排除问题:
看一下命令有没有使用绝对路径,比如这里使用/usr/local/php/bin/php而不是php,使用/data/wwwroot/test/artisan而不是artisan。
如果已经使用了绝对路径还是不执行,那就直接在命令行输入/usr/local/php/bin/php /data/wwwroot/test/artisan schedule:run 1>> /dev/null 2>&1,看看有没有执行,如果没有执行,那就是laravel代码的问题,如果执行了说明是环境变量的问题,好好检查路径的问题。如果不知道php在什么地方,在命令行输入which php,就会提示你php安装在什么位置了。
2)定义调度
可以在
App\Console\Kernel类的
schedule方法中定义所有调度任务。
<?php namespace App\Console; use Illuminate\Console\Scheduling\Schedule; use Laravel\Lumen\Console\Kernel as ConsoleKernel; class Kernel extends ConsoleKernel { /** * The Artisan commands provided by your application. * * @var array */ protected $commands = [ \App\Console\Commands\ICO\SendEmail::class, ]; /** * Define the application's command schedule. * * @param \Illuminate\Console\Scheduling\Schedule $schedule */ protected function schedule(Schedule $schedule) { // 5 minutes every $schedule->command('icoemails:send')->everyFiveMinutes(); } }
还可以调度闭包调用、Artisan命令和操作系统命令
自定义Artisan命令
php artisan make:console App/Console/Commands/ICO/SendEmail --command=icoemails:send
第四步:编写业务代码
如上步,我们的业务逻辑代码通过执行命令去执行,handle方法如下:
这里只写出发送邮件的代码:
$job = (new SendMail('', $e['email'], $title, $emailTempFile, $data))->onQueue('push_notify_' . rand(0, 4)); $res = app('Illuminate\Contracts\Bus\Dispatcher')->dispatch($job);
第五步:调试邮件适配
编写邮件模版的时候我们会发现有很多限制,这里有一个不错的总结:
从头开始构建一个HTML电子邮件模板
–感谢laravel学院对广大laravel爱好者的帮助
阅读更多- laravel 定时任务通过队列发送邮件
- Laravel 队列发送邮件
- 利用任务调度发送邮件
- Spring任务调度之Spring-Task--应用实例:实现邮件(带附件)定时发送功能
- Laravel中用Redis来做任务队列---出现重载问题
- 监控redis和zookpeer服务脚本 并且python发送邮件
- laravel利用队列发送邮件
- Spring的任务调度和邮件发送 推荐
- Laravel中利用队列发送邮件的方法示例
- Laravel 队列发送邮件
- laravel队列发送邮件报错
- Quartz 框架和cron表达式任务调度的例子(spring下实现定时发送邮件)
- [ Laravel 5.1 文档 ] 服务 —— 任务调度
- Django+Celery+Redis实现异步任务(发送邮件)
- laravel 邮件放入队列没有发送的问题
- Laravel中利用队列发送邮件的方法示例
- celery配合rabbitmq任务队列实现任务的异步调度执行[celery redis] 推荐
- 使用rundeck调度工具设置发送邮件
- git 远程版本库,github提供服务原理,git自动更新发送邮件
- Redis作为消息队列服务场景应用案例