laravel任务调度+命令行+邮件发送用例
起因
最近想把臭大佬的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
已经可以成功推送了。完成!