coollabsio/coolify · warning · Exception
Too many messages sent!
Error message
Too many messages sent!
What it means
The 'send test email' action wraps the mail in RateLimiter::attempt keyed `test-email:<teamId>` with a 10-second decay. When the limiter refuses the attempt it returns false and this exception is thrown via handleError. Note the configured allowance is `$perMinute = 0`: zero attempts are permitted, so with this config the limiter blocks the callback outright - if test emails never send at all, this is why.
Source
Thrown at app/Livewire/Notifications/Email.php:352
$this->validate([
'testEmailAddress' => 'required|email',
], [
'testEmailAddress.required' => 'Test email address is required.',
'testEmailAddress.email' => 'Please enter a valid email address.',
]);
$executed = RateLimiter::attempt(
'test-email:'.$this->team->id,
$perMinute = 0,
function () {
$this->team?->notifyNow(new Test($this->testEmailAddress, 'email'));
$this->dispatch('success', 'Test Email sent.');
},
$decaySeconds = 10,
);
if (! $executed) {
throw new \Exception('Too many messages sent!');
}
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function copyFromInstanceSettings()
{
$this->authorize('update', $this->settings);
$settings = instanceSettings();
$this->smtpFromAddress = $settings->smtp_from_address;
$this->smtpFromName = $settings->smtp_from_name;
if ($settings->smtp_enabled) {
$this->smtpEnabled = true;
$this->resendEnabled = false;
}
View on GitHub (pinned to 70b9acc424)
Solutions
- Wait out the 10-second decay window and click once
- If the test email never sends at all, raise the allowance in app/Livewire/Notifications/Email.php to at least 1 (e.g. `$perMinute = 2`) - zero is not a valid 'allow' value for RateLimiter::attempt
- If a stale limiter entry is suspected, clear the cache key `test-email:<teamId>` (redis/cache driver)
Example fix
// before
$executed = RateLimiter::attempt(
'test-email:'.$this->team->id,
$perMinute = 0,
fn () => $this->team?->notifyNow(new Test($this->testEmailAddress, 'email')),
$decaySeconds = 10,
);
// after - allow 2 test mails per 10s window
$executed = RateLimiter::attempt(
'test-email:'.$this->team->id,
$perMinute = 2,
fn () => $this->team?->notifyNow(new Test($this->testEmailAddress, 'email')),
$decaySeconds = 10,
); Defensive patterns
Strategy: retry
Validate before calling
// surface remaining wait time instead of throwing
$key = 'test-email:'.$this->team->id;
if (RateLimiter::tooManyAttempts($key, $perMinute)) {
$seconds = RateLimiter::availableIn($key);
$this->dispatch('error', "Retry in {$seconds}s.");
return;
}
RateLimiter::hit($key, 10); // then send Try / catch
Catch \Throwable with handleError as the component already does, and translate 'Too many messages sent!' into a countdown message; also verify the allowance passed to RateLimiter::attempt is >= 1, since 0 blocks every attempt.
Prevention
- Disable the send button client-side for the decay window after each click
- Never pass 0 as the attempt allowance - it refuses all attempts, not 'first one free'
- Key the limiter per team (as shown) so one team's tests never block another's
When it happens
Trigger: Clicking 'Send test email' again inside the 10-second decay window; more precisely, with the shown `$perMinute = 0` the limiter refuses every call (0 >= 0 in tooManyAttempts), so each click after the limit semantics applies throws instead of sending.
Common situations: Impatient double-clicks on the test button; a misconfigured attempt count of 0 making the button fail deterministically; several team members testing notifications simultaneously.
Related errors
- No email recipients found
- Recipient is not part of the team
- Invalid Cron / Human expression
- No email settings found.
- No email settings found.
AI-assisted analysis of coollabsio/coolify@70b9acc424 (2026-08-17).
Data as JSON: /api/errors/c5fcb55d6a08091f.
Report an issue: GitHub.