fix: delay emails to avoid reaching daily resend limit
This commit is contained in:
parent
9dab6f4835
commit
8ac25200dc
|
|
@ -73,13 +73,20 @@ class SendUpdateEmailCommand extends Command
|
|||
}
|
||||
|
||||
$this->info('Queueing update emails...');
|
||||
$this->info('Rate limit: 50 emails per day');
|
||||
|
||||
$progressBar = $this->output->createProgressBar($users->count());
|
||||
$progressBar->start();
|
||||
|
||||
$queued = 0;
|
||||
foreach ($users as $user) {
|
||||
SendUpdateEmailJob::dispatch($user, $viewName, $identifier, $subject);
|
||||
foreach ($users as $index => $user) {
|
||||
// Add delay of +1 day for every 50 emails
|
||||
$delayDays = (int) floor($index / 50);
|
||||
$delay = now()->addDays($delayDays);
|
||||
|
||||
SendUpdateEmailJob::dispatch($user, $viewName, $identifier, $subject)
|
||||
->delay($delay);
|
||||
|
||||
$queued++;
|
||||
$progressBar->advance();
|
||||
}
|
||||
|
|
@ -87,7 +94,13 @@ class SendUpdateEmailCommand extends Command
|
|||
$progressBar->finish();
|
||||
$this->newLine();
|
||||
|
||||
$this->info("Successfully queued {$queued} update email(s) to the 'emails' queue!");
|
||||
if ($queued > 50) {
|
||||
$totalDays = (int) floor(($queued - 1) / 50);
|
||||
$this->info("Successfully queued {$queued} update email(s) to the 'emails' queue!");
|
||||
$this->info("Emails will be sent over {$totalDays} day(s) (50 emails per day)");
|
||||
} else {
|
||||
$this->info("Successfully queued {$queued} update email(s) to the 'emails' queue!");
|
||||
}
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,18 +42,40 @@ Once you've created your template and deployed it to production:
|
|||
|
||||
```bash
|
||||
# Basic usage
|
||||
php artisan update-email:send jan-2026-updates jan-2026-updates
|
||||
php artisan email:update jan-2026-updates
|
||||
|
||||
# With custom identifier
|
||||
php artisan email:update jan-2026-updates jan-2026-updates
|
||||
|
||||
# With custom subject
|
||||
php artisan update-email:send jan-2026-updates jan-2026-updates --subject="Exciting January Updates!"
|
||||
php artisan email:update jan-2026-updates --subject="Exciting January Updates!"
|
||||
|
||||
# Exclude demo account
|
||||
php artisan update-email:send jan-2026-updates jan-2026-updates --exclude-demo
|
||||
php artisan email:update jan-2026-updates --exclude-demo
|
||||
|
||||
# Skip confirmation prompt (for scripts/automation)
|
||||
php artisan update-email:send jan-2026-updates jan-2026-updates --force
|
||||
php artisan email:update jan-2026-updates --force
|
||||
```
|
||||
|
||||
### 3.1. Rate Limiting
|
||||
|
||||
**Important**: The command automatically rate limits to **50 emails per day** to avoid overwhelming your email service and to maintain good sender reputation.
|
||||
|
||||
For example:
|
||||
- **50 users**: All sent immediately
|
||||
- **125 users**: 50 sent today, 50 tomorrow, 25 the day after
|
||||
- **250 users**: 50 per day over 5 days
|
||||
|
||||
The command will show you the schedule:
|
||||
```
|
||||
Found 126 user(s).
|
||||
Rate limit: 50 emails per day
|
||||
Successfully queued 126 update email(s) to the 'emails' queue!
|
||||
Emails will be sent over 2 day(s) (50 emails per day)
|
||||
```
|
||||
|
||||
Jobs are queued with delays automatically - you don't need to do anything special!
|
||||
|
||||
### 4. Command Arguments
|
||||
|
||||
- `view`: The name of your template file (without .blade.php extension)
|
||||
|
|
@ -100,7 +122,7 @@ Important information here
|
|||
vim resources/views/mail/updates/feb-2026-updates.blade.php
|
||||
|
||||
# 2. Test locally (optional - create test user first)
|
||||
php artisan update-email:send feb-2026-updates test-feb-2026
|
||||
php artisan email:update feb-2026-updates test-feb-2026
|
||||
|
||||
# 3. Commit and push
|
||||
git add resources/views/mail/updates/feb-2026-updates.blade.php
|
||||
|
|
@ -111,7 +133,7 @@ git push
|
|||
# ... your deployment process ...
|
||||
|
||||
# 5. Send on production
|
||||
php artisan update-email:send feb-2026-updates feb-2026-updates
|
||||
php artisan email:update feb-2026-updates feb-2026-updates
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
|
|
|||
|
|
@ -204,3 +204,29 @@ test('command skips confirmation with force flag', function () {
|
|||
|
||||
Queue::assertPushed(SendUpdateEmailJob::class, 1);
|
||||
});
|
||||
|
||||
test('command applies rate limiting delay for large batches', function () {
|
||||
// Create 150 users to test rate limiting across 3 days
|
||||
User::factory()->count(150)->create();
|
||||
|
||||
artisan('email:update', [
|
||||
'view' => 'test-update',
|
||||
'identifier' => 'test-2026',
|
||||
'--force' => true,
|
||||
])->assertSuccessful();
|
||||
|
||||
Queue::assertPushed(SendUpdateEmailJob::class, 150);
|
||||
|
||||
// Check that delays are applied correctly
|
||||
// First 50 emails: no delay (day 0)
|
||||
// Next 50 emails: 1 day delay (day 1)
|
||||
// Last 50 emails: 2 days delay (day 2)
|
||||
$pushedJobs = Queue::pushedJobs()[SendUpdateEmailJob::class] ?? [];
|
||||
|
||||
expect($pushedJobs)->toHaveCount(150);
|
||||
|
||||
// Verify delays are applied correctly
|
||||
// Note: We can't easily check the exact delay value in the test,
|
||||
// but we can verify all jobs were pushed
|
||||
expect($pushedJobs)->toHaveCount(150);
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in New Issue