laravel任务调度+命令行+邮件发送用例

臭大佬 2019-11-16 22:41:49 3087
简介 任务调度实现定时->调用命令行->执行邮件发送功能->发送给我推送结果

起因

最近想把臭大佬的seo搞起来,所以想让百度更好的收录网站:

主动推送和自动推送是互补的,在自动推送的同时,想实现一个主动推送的功能,这里我的思路是利用laravel的任务调度+Artisan命令+邮件系统去实现

流程

任务调度实现定时->调用命令行->执行邮件发送功能->发送推送结果

邮箱功能

Laravel 支持多种邮件驱动,包括 smtp、Mailgun、Maildrill、Amazon SES、mail 和 sendmail。Mailgun 、 Maildrill 都是第三方邮件服务。mail 驱动使用 PHP 提供的 mail 函数。sendmail 驱动通过 Sendmail/Postfix(Linux)提供的命令发送邮件,smtp 驱动使用支持 ESMTP 的 SMTP 服务器发送邮件。mail 不安全,sendmail 需要安装配置 Sendmail/Postfix,并且信用不高,很容易被当成垃圾邮件,第三方服务的信用是最高的,商业软件推荐使用。

配置

我们以 QQ 邮箱为例,我们将开启 QQ 的 SMTP 功能,并配置项目的 SMTP 邮件发送功能。其他邮箱的配置基本大致相同。

开启 QQ 邮箱的 SMTP 支持

首先我们需要在 QQ 邮箱的账号设置里开启 POP3 和 SMTP 服务。具体请查看 如何打开POP3/SMTP/IMAP功能? 。

只需要开启以下:

需要开启POP3和SMTP服务(QQ邮箱登录=》选择设置=》账户=》开启POP3;

配置的时候需要发送短信进行验证,然后会给你返回一个授权码,需要保存这个授权码,

修改.env

当设置成功后,需要在.env配置

MAIL_DRIVER=smtp
MAIL_HOST=smtp.qq.com
MAIL_PORT=465
MAIL_USERNAME="1937832819@qq.com"
MAIL_FROM_ADDRESS="1937832819@qq.com"
MAIL_PASSWORD="刚才的授权码"
MAIL_FROM_NAME="邮箱名称"
MAIL_ENCRYPTION=ssl
//双引号处需要修改,别的默认

注释:
MAIL_DRIVER=smtp —— 使用支持 ESMTP 的 SMTP 服务器发送邮件;
MAIL_HOST=smtp.qq.com —— QQ 邮箱的 SMTP 服务器地址,必须为此值;
MAIL_PORT=465 —— QQ 邮箱的 SMTP 服务器端口,必须为此值;
MAIL_USERNAME=xxxx_#_@_#_qq.com —— 请将此值换为你的 QQ + @qq.com;
MAIL_PASSWORD=xxxxxxxxx —— 密码是我们拿到的授权码;
MAIL_ENCRYPTION=SSL —— 加密类型,选项 null 表示不使用任何加密,其他选项还有 TLS,这里我们使用 SSL 即可。
MAIL_FROM_ADDRESS=xxxxxxxxx_#_@_#_qq.com —— 此值必须同MAIL_USERNAME 一致;
MAIL_FROM_NAME=用来作为邮件的发送者名称。

 

编写Mail

 

php artisan make:mail Alarm

编写一个简单的发送内容:

<?php

namespace App\Mail;

use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;

class Alarm extends Mailable
{
    use Queueable, SerializesModels;

    /**
     * @var string
     */
    private $content = '';

    /**
     * Alarm constructor.
     * @param $text
     */
    public function __construct($text)
    {
        //设置主题
        $this->subject(env('MAIL_FROM_NAME'));
        //设置发件人
        $this->from(env('MAIL_FROM_ADDRESS'), env('MAIL_FROM_NAME'));
        //设置内容
        $this->setContent($text);
    }

    /**
     * Description:发送
     * User: Vijay
     * Date: 2019/11/16
     * Time: 12:54
     * @return Alarm
     */
    public function build()
    {
        return $this->view('emails.alarm.text')->with([
            'title' => env('MAIL_FROM_NAME'),
            'content' => $this->content,
        ]);
    }

    /**
     * Description:设置发送内容
     * User: Vijay
     * Date: 2019/11/16
     * Time: 13:10
     * @param string $text
     * @return $this
     */
    public function setContent($text = '')
    {
        $this->content .= '时间:' . date('Y-m-d H:i:s') . ',';
        $this->content .= '内容:' . $text;
        return $this;
    }
}

 

建立相应视图

 

// resources/views/emails/alarm/text.blade.php
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{{ $tilte }}</title>
</head>
<body>
<div>{{ $content }}</div>
</body>
</html>

 

模板方式发送

使用官网提供的方式发送,写法如下(也就是配合上面的内容发送)

$toUser = '1937832819@qq.com';
$res = Mail::to($toUser)->send(new Alarm('推送成功'));

这里需要使用到编写好的命令行,这边为了统一说明邮箱功能,所以,先写在这里,执行我们编写好的命令行(参考下面方式一)

php artisan send:LinkSubmit

运行结果

模板匿名函数发送

调用Mail::send()发送,

//方式二
$subject = env('MAIL_FROM_NAME');
Mail::send('emails.alarm.text', [
    'name' => env('MAIL_FROM_NAME'),
    'title' => env('MAIL_FROM_NAME'),
    'content' => $msg,
], function ($message) use ($toUser, $subject) {
    $message->to($toUser)->subject($subject);
    //发送附件
    //$attachment = storage_path('xls/files/test.xls');
    //$message->attach($attachment, ['as' => '中文文档.xls']);
});

Mail::send();需要传三个参数,第一个为引用的模板,第二个为给模板传递的变量,第三个为一个闭包,参数绑定Mail类的一个实例。

发送纯文本邮件

 

Mail::raw($msg, function ($message) use ($toUser, $subject) {
     $message->to($toUser)->subject($subject);
});

错误处理

 

if (count(Mail::failures()) < 1) {
   $this->info('发送邮件成功,请查收!');
} else {
   $this->info('发送邮件失败,请重试!');
}

编写artisan命令

 

生成命令

 

 php artisan make:command SendLinkSubmit

内容如下:

<?php

namespace App\Console\Commands;

use App\Mail\Alarm;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Mail;

class SendLinkSubmit extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'send:linkSubmit';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = '向百度主动提交链接';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Description:
     * User: Vijay
     * Date: 2019/11/16
     * Time: 13:00
     */
    public function handle()
    {
        //
        $urls = array(
            'https://www.choudalao.com/',
            'xxxx',
        );
        //百度接口
        $api = 'xxxx';
        $ch = curl_init();
        $options = array(
            CURLOPT_URL => $api,
            CURLOPT_POST => true,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_POSTFIELDS => implode("\n", $urls),
            CURLOPT_HTTPHEADER => array('Content-Type: text/plain'),
        );
        curl_setopt_array($ch, $options);
        $result = curl_exec($ch);
        $res = json_decode($result, true);
        $this->info($result);
        $toUser = 'xxx@qq.com';
        if (isset($res['success'])) {
            $msg = '推送成功';
            $this->info($msg . $res['success'] . '条');
        } else {
            $msg = $res['message'] ?? '请求过于频繁';
            $this->info('推送失败');
            $this->info('原因:' . $msg);
            $subject = env('MAIL_FROM_NAME');
            /*//方式一
            Mail::to($toUser)->send(new Alarm($msg));
            //方式二
            Mail::send('emails.alarm.text', [
                'name' => env('MAIL_FROM_NAME'),
                'title' => env('MAIL_FROM_NAME'),
                'content' => $msg,
            ], function ($message) use ($toUser, $subject) {
                $message->to($toUser)->subject($subject);
                //发送附件
                //$attachment = storage_path('xls/files/test.xls');
                //$message->attach($attachment, ['as' => '中文文档.xls']);
            });*/
            //方式三 发送纯文本
            Mail::raw($msg, function ($message) use ($toUser, $subject) {
                $message->to($toUser)->subject($subject);
            });
            //错误处理
            if (count(Mail::failures()) < 1) {
                $this->info('发送邮件成功,请查收!');
            } else {
                $this->info('发送邮件失败,请重试!');
            }
        }
    }
}

 

调用

SendLinkSubmit类中,protected $signature = 'send:linkSubmit';设置的是命令名称,protected $description = '向百度主动提交链接';设置的是命令描述,所以到网站根目录下。运行如下命令就可以执行public function handle()里面的代码。

php artisan send:LinkSubmit

定时任务

在编写好artisan命令后(也就是SendLinkSubmit。php),我们在Kernel.php,command 方法传递命令名称或者类来调度一个 Artisan 命令。并写入计划任务

 **
     * 应用中自定义的 Artisan 命令
     * The Artisan commands provided by your application.
     *
     * @var array
     */
    protected $commands = [
        //
        //LogInfo::class,
        SendLinkSubmit::class,
    ];

    /**
     * 定义计划任务
     * Define the application's command schedule.
     *
     * @param  \Illuminate\Console\Scheduling\Schedule  $schedule
     * @return void
     */
    protected function schedule(Schedule $schedule)
    {
        // $schedule->command('inspire')
        //          ->hourly();
        //log
        //$schedule->command('lesson:log')->everyMinute();
        $schedule->command('send:linkSubmit')->everyMinute();
    }

启用调度器

当我们编辑好我们的定时任务后,我们只需要到我们网站的根目录下,启动调度器就可以了。

找到当前站点运行的php版本

 

php -v

我这边有两个php版本,但是运行的是7.3.11版本的。

查找PHP.ini文件所在的位置

 

sudo  find / -name php.ini

 
运行文件在对应的bin里面
 

/www/server/php/73/bin/php

 

 

执行crontab -e 在里面添加下面的cron入口

 

sudo crontab -e

在里面加入* * * * * /www/server/php/73/bin/php /www/wwwroot/www.choudalao.com/artisan schedule:run >> /dev/null 2>&1,保存退出。

*  * * * * /www/server/php/73/bin/php /www/wwwroot/www.choudalao.com/artisan schedule:run >> /dev/null 2>&1

/www/server/php/73/bin/php是PHP文件所在的位置
/www/wwwroot/www.choudalao.com/artisan 是项目根目录
* * * * * 指这个 Cron 为每分钟执行一次 Laravel 的命令行调度器
当 schedule:run 命令被执行的时候,Laravel 会根据你的调度执行预定的程序。

执行

完成以上工作后,其实已经加到定时任务了,也可以执行命令运行查看效果。

php artisan schedule:run

已经可以成功推送了。完成!