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

  1. Wait out the 10-second decay window and click once
  2. 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
  3. 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

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


AI-assisted analysis of coollabsio/coolify@70b9acc424 (2026-08-17). Data as JSON: /api/errors/c5fcb55d6a08091f. Report an issue: GitHub.