{"record":{"id":"c3142e3f4bb18850","repo":"monicahq/monica","slug":"only-email-can-be-sent","errorCode":null,"errorMessage":"Only email can be sent.","messagePattern":"Only email can be sent\\.","errorType":"exception","errorClass":"Exception","httpStatus":500,"severity":"error","filePath":"app/Domains/Settings/ManageNotificationChannels/Services/SendTestEmail.php","lineNumber":63,"sourceCode":"    public function execute(array $data): UserNotificationChannel\n    {\n        $this->data = $data;\n        $this->validate();\n        $this->send();\n        $this->log();\n\n        return $this->userNotificationChannel;\n    }\n\n    private function validate(): void\n    {\n        $this->validateRules($this->data);\n\n        $this->userNotificationChannel = $this->author->notificationChannels()\n            ->findOrFail($this->data['user_notification_channel_id']);\n\n        if ($this->userNotificationChannel->type !== UserNotificationChannel::TYPE_EMAIL) {\n            throw new Exception('Only email can be sent.');\n        }\n    }\n\n    private function send(): void\n    {\n        Mail::to($this->userNotificationChannel->content)->send(\n            new TestEmailSent($this->userNotificationChannel)\n        );\n    }\n\n    private function log(): void\n    {\n        UserNotificationSent::create([\n            'user_notification_channel_id' => $this->userNotificationChannel->id,\n            'sent_at' => Carbon::now(),\n            'subject_line' => trans('Test email for Monica'),\n        ]);\n    }","sourceCodeStart":45,"sourceCodeEnd":81,"githubUrl":"https://github.com/monicahq/monica/blob/e08e91734170b6bbd582cb578532c3948196124e/app/Domains/Settings/ManageNotificationChannels/Services/SendTestEmail.php#L45-L81","documentation":"SendTestEmail sends a test message on a user notification channel. It loads the channel belonging to the author via findOrFail (unknown id -> 404) and then requires type === UserNotificationChannel::TYPE_EMAIL ('email'); any other type throws a bare \\Exception which Laravel renders as a 500.","triggerScenarios":"Invoking the 'send test email' action with the user_notification_channel_id of a channel whose type is 'telegram' (the only other type in this codebase) — typically a stale frontend still holding an id from before the channel was created or switched.","commonSituations":"UI channel list not refreshed after editing channels, mixed-up ids between the email and telegram channel forms, or API consumers hard-coding the wrong channel id.","solutions":["Pass the id of a channel whose type is 'email'","Reload the notification channels list before triggering the test send","Only offer 'send test email' for email channels in the UI","Catch the exception in the controller and return 422 with the message instead of a 500"],"exampleFix":"// before\napp(SendTestEmail::class)->execute([\n    'user_notification_channel_id' => $channelId, // might be a telegram channel\n]);\n\n// after\n$channel = $author->notificationChannels()->findOrFail($channelId);\nabort_unless($channel->type === UserNotificationChannel::TYPE_EMAIL, 422, 'Only email can be sent.');\napp(SendTestEmail::class)->execute([\n    'user_notification_channel_id' => $channel->id,\n]);","handlingStrategy":"validation","validationCode":"// Validate before calling: the channel must exist and be an email channel\n$channel = $author->notificationChannels()->find($data['user_notification_channel_id']);\n\nif ($channel === null) {\n    throw ValidationException::withMessages(['user_notification_channel_id' => 'Channel not found.']);\n}\nif ($channel->type !== UserNotificationChannel::TYPE_EMAIL) {\n    throw ValidationException::withMessages(['user_notification_channel_id' => 'Only email channels can receive a test email.']);\n}","typeGuard":"function isEmailChannel(?UserNotificationChannel $channel): bool\n{\n    return $channel !== null\n        && $channel->type === UserNotificationChannel::TYPE_EMAIL;\n}","tryCatchPattern":"try {\n    app(SendTestEmail::class)->execute($data);\n} catch (\\Exception $e) {\n    if ($e->getMessage() === 'Only email can be sent.') {\n        // wrong channel type: surface as 422 and refresh the channel list\n        throw ValidationException::withMessages(['user_notification_channel_id' => $e->getMessage()]);\n    }\n    throw $e;\n}","preventionTips":["Refresh the channel list before showing per-channel test actions","Bind test actions to the channel type at render time (email button only on email rows)","Scope channel selection queries to type where the operation is type-specific","Map this \\Exception to 422 at the boundary so clients never see a 500"],"tags":["monica","notifications","email","channel-type"],"backgroundTag":"channel-type-mismatch","analyzedSha":"e08e91734170b6bbd582cb578532c3948196124e","analyzedAt":"2026-08-17T01:36:49.014Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}