1. Tạo command
Chạy lệnh
php artisan make:command SendDailyEmail
sinh ra file
app/Console/Commands/SendDailyEmail.php
2. Chỉnh sửa app/Console/Commands/SendDailyEmail.php
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Mail;
use App\Mail\DailyReportMail;
class SendDailyEmail extends Command
{
/**
* Tên command để gọi bằng artisan
*/
protected $signature = 'app:send-daily-email';
/**
* Mô tả command
*/
protected $description = 'Gửi email báo cáo hằng ngày lúc 8h00';
/**
* Thực thi command
*/
public function handle()
{
// Danh sách email nhận
$emails = [
'example1@gmail.com',
'example2@gmail.com',
];
foreach ($emails as $email) {
Mail::to($email)->send(new DailyReportMail());
}
$this->info('Đã gửi email hằng ngày thành công!');
}
}
3. Đăng ký Task Scheduler (QUAN TRỌNG)
3.1. Với Laravel <= 10
File: app/Console/Kernel.php
<?php
namespace App\Console;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
class Kernel extends ConsoleKernel
{
protected function schedule(Schedule $schedule): void
{
$schedule->command('app:send-daily-email')
->dailyAt('09:00')
->timezone('Asia/Ho_Chi_Minh')
->onSuccess(function () {
Log::info('Send daily email successfully');
})
->onFailure(function () {
Log::error('Send daily email failed');
});
}
}
Giải thích từng dòng
dailyAt('09:00') Chạy đúng 9h sáng
timezone() Đúng giờ Việt Nam
withoutOverlapping() Không chạy chồng nếu task cũ chưa xong
onOneServer() Tránh chạy nhiều lần khi dùng nhiều server
appendOutputTo() Ghi log để debug
3.2. Với Laravel 11 và 12
Toàn bộ đăng ký command & schedule đều đặt ở đây
routes/console.php
<?php
use Illuminate\Support\Facades\Schedule;
Schedule::command('app:send-daily-email')
->dailyAt('09:00')
->timezone('Asia/Ho_Chi_Minh')
->withoutOverlapping()
->onOneServer()
->appendOutputTo(storage_path('logs/daily_email.log'));
Nếu bạn chưa có routes/console.php?
Chạy:
php artisan install:api
Hoặc tạo thủ công:
routes/console.php
Laravel sẽ nhận file này ngay, không cần khai báo thêm.
4. Cấu hình CRON trên Server (BẮT BUỘC)
Mở cron:
crontab -e
Thêm dòng sau:
* * * * * cd /var/www/your-project && php artisan schedule:run >> /dev/null 2>&1
Ý nghĩa:
Mỗi 1 phút, cron gọi schedule:run
Laravel tự quyết định task nào đến giờ thì chạy
+ Kiểm tra tác vụ đã đăng ký chưa
cd /var/www/your-project/
php artisan schedule:list
Bạn sẽ thấy dạng:
0 9 * * * php artisan trans:send-unconfirmed-report ................... Next Due: 23 giờ tới
30 10 * * * php artisan calculator:update ................................ Next Due: 55 phút tới
0 8 * * * php artisan app:send-daily-email ............................. Next Due: 24 giờ tới
+ Kiểm tra gửi mail thủ công
php artisan app:send-daily-email
Nếu mail gửi ok → scheduler chắc chắn chạy được