やりたいこと
・Laravel 9(PHP 8)で、毎日朝4時に「ポートフォリオの作成日数」をユーザーの登録メール宛に送信したい。
・ユーザーごとに「未完了のポートフォリオ」の経過日数を計算して通知する。
環境
Laravel 9
PHP 8
Mailpit
実装手順
① Artisanコマンドを作成
php artisan make:command SendDevDaysNotification
作成されるファイル:
app/Console/Commands/SendDevDaysNotification.php
② Markdown対応の通知クラスを作成
php artisan make:notification DevDaysNotification --markdown=emails.devdays
作成されるファイル:
# 通知(Notification)クラス本体
app/Notifications/DevDaysNotification.php
# メールのMarkdownテンプレート
resources/views/emails/devdays.blade.php
③コマンドに処理を書く
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Models\User;
use App\Notifications\DevDaysNotification;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
class SendDevDaysNotification extends Command
{
protected $signature = 'notify:send-devdays';
protected $description = '毎朝、DevDaysの経過日数を通知';
public function handle()
{
$users = User::with(['counts' => function ($q) {
$q->where('is_completed', false)->latest('started_at');
}])->get();
foreach ($users as $user) {
$count = $user->counts->first();
if ($count) {
$days = Carbon::parse($count->started_at)->diffInDays(now());
$user->notify(new DevDaysNotification($user->name, $days));
Log::info("通知を送信: {$user->email}({$days}日)");
}
}
$this->info('通知の送信が完了しました。');
}
}
④Notificationの中身を書く
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Notifications\Messages\MailMessage;
class DevDaysNotification extends Notification
{
use Queueable;
protected $name;
protected $days;
public function __construct($name, $days)
{
$this->name = $name;
$this->days = $days;
}
public function via($notifiable)
{
return ['mail'];
}
public function toMail($notifiable)
{
return (new MailMessage)
->subject('【DevDays】現在の経過日数のお知らせ')
->markdown('emails.devdays', [
'name' => $this->name,
'days' => $this->days,
]);
}
}
⑤Markdownメールテンプレートを書く
@component('mail::message')
# DevDays 経過日数のご案内
{{ $name ?? 'お客様' }} さん、こんにちは!
現在の DevDays は開始から **{{ $days }}日** 経過しました。
引き続きがんばっていきましょう!
@endcomponent
⑥スケジュール登録(毎朝4時)
protected function schedule(Schedule $schedule)
{
$schedule->command('notify:send-devdays')->dailyAt('04:00');
}
⑦通知のキュー処理対応(任意)
▶️ キューなし(同期処理)の場合
そのまま使えます。
$user->notify(...) 実行時に、即座にメールが送られます。
キュー設定やワーカー起動も 不要 です。
ただし、通知対象が多いとコマンド実行が重くなります。
▶️ キューあり(非同期処理)の場合
大量ユーザーに通知を送る場合は、キューを使うことで高速かつ安全に送れます。
⑦-① .env をキュー用に変更
QUEUE_CONNECTION=database
補足
開発中は .env を
# QUEUE_CONNECTION=database
QUEUE_CONNECTION=sync
に戻すと、即時送信されるのでデバッグしやすくなります。
⑦-② ジョブテーブルを作成・マイグレート
php artisan queue:table
php artisan migrate
jobs テーブルが生成され、通知がここに一旦蓄積されます。
⑦-③ queue:work を起動(メールを送信する実行プロセス)
php artisan queue:work
上記コマンドを起動しておくことで、jobs テーブルにたまった通知が順番に処理されます。
⑧テスト実行(手動)
pwd
# /Applications/MAMP/htdocs/Laravel(任意フォルダ)/dev_days(任意プロジェクト名)
mailpit
# http://localhost:8025/ にログイン
php artisan notify:send-devdays
mailpit 設定方法
⑨スケジュール確認用テスト(1分ごとに実行)
protected function schedule(Schedule $schedule)
{
// $schedule->command('notify:send-devdays')->dailyAt('04:00');
// スケジュールを一時的に変更:
$schedule->command('notify:send-devdays')->everyMinute();
}
実行コマンド:
php artisan schedule:run
⑩本番環境(エックスサーバー):cron + queue:work
① Laravelの .env を queue対応にしておく
QUEUE_CONNECTION=database
② php artisan queue:table と php artisan migrate を 本番でも実行しておく
php artisan queue:table
php artisan migrate
※ jobs テーブルが本番DBに作られていないとキューは動きません。
③ cronの登録(Xserverのサーバーパネル → cron設定)
以下を1分ごとに登録:
* * * * * cd /home/akkun1114/akkun1114.com/your_project && /usr/bin/php8.1 artisan queue:work --stop-when-empty >> /dev/null 2>&1
補足:
/home/akkun1114/akkun1114.com/your_project ← Laravelプロジェクトのルート
/usr/bin/php8.1 ← 実行するPHPのパス(Xserverのサーバーパネルから確認可能)
④ スケジュール実行のための schedule:run も別途必要(Xserverのサーバーパネル → cron設定)
実は queue:work だけではスケジュール登録された Artisanコマンド(notify:send-devdays)が動きません。
なので、もう1本、以下のcronも登録する:
* * * * * cd /home/akkun1114/akkun1114.com/your_project && /usr/bin/php8.1 artisan schedule:run >> /dev/null 2>&1
どうなるか?
・毎分cronで queue:work を1回だけ実行
・jobs テーブルにキューがあれば1つずつ処理して終わる
・処理がなくなればすぐ終了する
・Supervisor とは違い、常駐しない(共有サーバー向けの運用)
まとめ:エックスサーバーでのキュー対応はこうする
項目 | 対応方法 |
---|---|
Supervisor | ❌ 使用不可 |
systemd | ❌ 使用不可 |
queue:work を常駐 | ❌ 不可 |
対応策 | ✅ cron + --stop-when-empty を毎分実行 |
おまけ
.env の設定サンプル
MAIL_MAILER=smtp
MAIL_HOST=localhost
MAIL_PORT=1025
MAIL_FROM_ADDRESS="hello@example.com"
MAIL_FROM_NAME="DevDays"
QUEUE_CONNECTION=database
関連