Laravel5.6 使用定时任务实现定时发邮件

本文方法是利用Linux的crontab定时任务来协助实现Laravel的任务调度

一、创建项目

1、打开终端,执行命令:laravel new crontab,包括数据库,确保本地能正常运行。随后部署上线。phpstrom连接服务器,确保代码可以正常提交到服务器。
2、创建任务类,终端执行命令:php artisan make:command SendEmail
3、修改 SendEmail.php 文件

protected $signature = 'email:send';
protected $description = '定时发邮件测试';

4、先不慌做发邮件,先来个文件定时写入测试,在文件中写入当前时间,代码如下

public function handle()
{
  //写入文件
  file_put_contents("/var/www/crontab/file.txt", date('Y-m-d H:i:s') . PHP_EOL, FILE_APPEND);
}

注:这里的PHP_EOL代表时间列表换行,后面的FILE_APPEND是指往后追加一条记录。

5、修改app/Console/Kernel.php文件:

protected $commands = [
    Commands\SendEmail::class //注册任务类
];

protected function schedule(Schedule $schedule)
{
    //每分钟执行一次文件的写入
    $schedule->command('email:send')
        ->everyMinute();
}

6、服务器上,进入项目:cd /var/www/crontab,先查看服务器上PHP安装路径,执行命令:which php,我的PHP路径是/usr/bin/php,然后把路径复制保存下来,接着执行命令:crontab -e,选择打开方式,建议选择第4个。在最后一行增加如下代码:

* * * * * /usr/bin/php /var/www/crontab/artisan schedule:run >> /dev/null 2>&1

注:这里前面一部分/usr/bin/php代表服务器上PHP的安装路径,后面一部分代表项目目录。
另外上面的命令前面的5个星号*分别代表分钟、小时、天、月、星期。
分钟:0-59的整数,默认星号和星号/1 代表1分钟。
小时:0-23的整数。
天:1-31的整数。
月:1-12的整数。
星期:0-7的整数,0和7都代表星期日。
crontab -l 可以列出当前的定时任务。

7、启动任务sudo service cron restart,打开FZ,查看服务器上项目的根目录下的file.txt文件中是否有时间写入并且每分钟执行一次。确认成功后,执行命令 service cron stopexit退出定时任务。

二、实现定时发邮件

接下来要做的是把写入文件的操作换成定时发邮件。在.env文件配置发邮件所需的相关信息。

MAIL_DRIVER=smtp
MAIL_HOST=smtp.qq.com
MAIL_PORT=465
MAIL_USERNAME=244500972@qq.com
MAIL_PASSWORD=***** //填自己的邮箱密码
MAIL_ENCRYPTION=ssl
MAIL_FROM_ADDRESS=244500972@qq.com
MAIL_FROM_NAME=huangdj

1、打开web.php,添加路由

$this->any('mail', 'HomeController@mail');//发邮件

2、在Home控制器中添加如下代码:

public function mail()
{
   //第一种方法
   \Mail::raw('定时发送邮件 测试', function ($message) {
       $message->from('244500972@qq.com', '长乐未央');
       $message->subject('邮件主题 测试');
       $message->to('244500972@qq.com');
   });

  //第二种方法
// \Mail::send('admin.mail', ['name' => 'holy'], function ($message) {
//     $message->to('244500972@qq.com');
// });
}

测试:终端打印路由,拿到路由地址去浏览器中访问:http://你的二级域名/admin/mail,查看邮箱是否收到邮件。如果成功收到邮件,请继续往下。。

3、打开任务类 SendEmail.php文件,修改handle方法,代码如下:

public function handle()
{
//写入文件
// file_put_contents("/var/www/crontab/file.txt", date('Y-m-d H:i:s') . PHP_EOL, FILE_APPEND);

 \Mail::raw('定时发送邮件 测试', function ($message) {
    //查出要发邮件的所有用户的邮箱
    $customers = Customer::where('email', '<>', null)->get();
    foreach ($customers as $customer) {
         $message->from('244500972@qq.com', 'huangdj');
         $message->subject('邮件主题 测试');

          //执行发送
         $message->bcc($customer->email);
      }
    });
}

最后去服务器的当前项目中,启动定时命令 service cron restart,等一分钟,查看邮箱是否收到邮件并且每一分钟执行一次。

三、增加Redis队列

当我们要发的邮件量很大时,我们就要使用到队列,把要发送的邮件全部存入队列,让后端去完成这个漫长的操作。网上很多资料都是使用数据库队列,我这里使用 redis队列。

1、修改.env文件中的 QUEUE_DRIVER=syncQUEUE_DRIVER=redis
2、启动队列,终端执行命令:redis-server,你会发现predis的扩展没装,执行命令:composer require predis/predis安装即可。安装完成后,重新启动redis。
3、创建任务类:php artisan make:job SendReminderEmail,运行成功后会在app/Jobs目录下生成一个SendReminderEmail.php,我们修改其内容如下:

<?php
namespace App\Jobs;

use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;

use App\Customer;
use Illuminate\Contracts\Mail\Mailer;
class SendReminderEmail implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
    protected $customer;
    /**
     * Create a new job instance.
     *
     * @return void
     */
    public function __construct(Customer $customer)
    {
        $this->customer = $customer;
    }

    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle(Mailer $mailer)
    {
        $customer = $this->customer;

        $mailer->send('emails.reminder',['customer'=>$customer],function($message) use ($customer){
            $message->to($customer->email)->subject('新功能发布');
        });
    }
}

4、创建邮件局部视图resources/views/emails/reminder.blade.php

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <div>
        亲爱的{{$customer->nickname}},您好,长乐未央新发布了Laravel5.6使用redis实现群发邮件功能,立即去体验下吧:
        <a href="https://www.whphp.com/">前往长乐未央</a>
    </div>
</body>
</html>

四、推送队列任务---手动分发任务

1、在web.php中添加如下路由:

Route::get('mail/sendReminderEmail/{id}','MailController@sendReminderEmail');

2、创建控制器:php artisan make:controller MailController,控制器中写入如下代码:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Http\Requests;
use App\Customer;
use Mail;
use Storage;
use App\Jobs\SendReminderEmail;
class MailController extends Controller
{
    //发送提醒邮件
    public function sendReminderEmail(Request $request, $id)
    {
        $customer = Customer::findOrFail($id);

        $this->dispatch(new SendReminderEmail($customer));
    }
}

3、运行队列监听器。在浏览器中访问http://你的二级域名/mail/sendReminderEmail/63,此时任务被推送到Redis队列中。在命令行中运行如下命令:php artisan queue:work,然后去查看邮箱会收到提醒邮件:

4、推送任务到指定队列,修改App\Console\Commands\SendEmail里面的handle方法代码如下:

public function handle()
{
  \Mail::queue('定时发送邮件 测试', function ($message) {
      //查出要发邮件的所有用户的邮箱
      $customers = Customer::where('email', '<>', null)->get();
      foreach ($customers as $customer) {
           $message->from('244500972@qq.com', 'huangdj');
           $message->subject('邮件主题 测试');

         //执行发送
        //$message->bcc($customer->email);

        //将任务推送到指定队列并延迟一分钟执行
        dispatch(new \App\Jobs\SendReminderEmail($customer->email))->onQueue('emails')->delay(60);
      }
  });
}

终极测试:看邮箱是否是每隔一分钟收到一份邮件
启动:redis-server
启动:php artisan queue:work
启动定时执行:service cron restart

参考文献:
http://laravelacademy.org/post/2012.html
http://laravelacademy.org/post/222.html#ipt_kb_toc_222_14

本作品采用《CC 协议》,转载必须注明作者和本文链接
huangdj
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!