1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

「バッチ処理」で経過日数を「毎朝4時」にメールで送る方法【Notification + バッチ処理を組むやり方】

Last updated at Posted at 2025-06-10

やりたいこと

・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

③コマンドに処理を書く

app/Console/Commands/SendDevDaysNotification.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の中身を書く

app/Notifications/DevDaysNotification.php

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メールテンプレートを書く

resources/views/emails/devdays.blade.php

@component('mail::message')
# DevDays 経過日数のご案内

{{ $name ?? 'お客様' }} さん、こんにちは!

現在の DevDays は開始から **{{ $days }}日** 経過しました。

引き続きがんばっていきましょう!

@endcomponent

⑥スケジュール登録(毎朝4時)

app/Console/Kernel.php

protected function schedule(Schedule $schedule)
{
    $schedule->command('notify:send-devdays')->dailyAt('04:00');
}

⑦通知のキュー処理対応(任意)

▶️ キューなし(同期処理)の場合

そのまま使えます。
$user->notify(...) 実行時に、即座にメールが送られます。
キュー設定やワーカー起動も 不要 です。
ただし、通知対象が多いとコマンド実行が重くなります。

▶️ キューあり(非同期処理)の場合

大量ユーザーに通知を送る場合は、キューを使うことで高速かつ安全に送れます。

⑦-① .env をキュー用に変更

.env
QUEUE_CONNECTION=database
補足

開発中は .env を

.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分ごとに実行)

app/Console/Kernel.php

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対応にしておく

.env
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 の設定サンプル

.env
MAIL_MAILER=smtp
MAIL_HOST=localhost
MAIL_PORT=1025
MAIL_FROM_ADDRESS="hello@example.com"
MAIL_FROM_NAME="DevDays"

QUEUE_CONNECTION=database

関連

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?