'boolean', 'smtp_port' => 'integer', 'google_oauth_connection_id' => 'integer', ]; public function scopeActive(Builder $query): Builder { return $query->where('is_active', true); } public function googleOAuthConnection(): BelongsTo { return $this->belongsTo(GoogleOAuthConnection::class); } protected function resolveOAuthToken(): string { if (!$this->relationLoaded('googleOAuthConnection')) { $this->load('googleOAuthConnection'); } $connection = $this->googleOAuthConnection; if (!$connection) { return ''; } try { return app(GoogleOAuthService::class)->getAccessToken($connection); } catch (\Exception $e) { return ''; } } public function getDecryptedPassword(): string { if ($this->auth_method === 'oauth') { return $this->resolveOAuthToken(); } if (empty($this->smtp_password)) { return ''; } try { return Crypt::decryptString($this->smtp_password); } catch (\Exception $e) { return $this->smtp_password; } } public function sanitizeName(): string { $name = $this->email_name ?? ''; if (filter_var($name, FILTER_VALIDATE_EMAIL)) { return 'Glastree'; } $name = preg_replace('/[^\p{L}\p{N}\s]/u', '', $name); $name = trim($name); return empty($name) ? 'Glastree' : $name; } public function getReplyTo(): ?string { if ($this->reply_to) { return $this->reply_to; } if ($this->verify_email) { return $this->verify_email; } return null; } public function buildDsn(): string { $password = $this->getDecryptedPassword(); $username = $this->smtp_username ?? $this->email_address; $encryption = $this->smtp_encryption ?? 'tls'; $scheme = ($encryption === 'ssl') ? 'smtps' : 'smtp'; return sprintf( '%s://%s:%s@%s:%d?encryption=%s', $scheme, rawurlencode($username), rawurlencode($password), $this->smtp_host ?? 'smtp.gmail.com', $this->smtp_port ?? 587, $encryption ); } public function buildSymfonyEmail(string $to, string $subject, string $body): \Symfony\Component\Mime\Email { $fromName = $this->sanitizeName(); $fromAddress = \Symfony\Component\Mime\Address::create($this->email_address, $fromName); $email = (new \Symfony\Component\Mime\Email()) ->from($fromAddress) ->to($to) ->subject($subject) ->text($body); $replyTo = $this->getReplyTo(); if ($replyTo) { $email->replyTo($replyTo); } return $email; } public function sendEmail(string $to, string $subject, string $body, array $attachmentPaths = []): void { $email = $this->buildSymfonyEmail($to, $subject, $body); foreach ($attachmentPaths as $path) { $email->attachFromPath($path); } if ($this->auth_method === 'oauth') { $mailer = $this->buildOAuthMailer(); } else { $transport = \Symfony\Component\Mailer\Transport::fromDsn($this->buildDsn()); $mailer = new \Symfony\Component\Mailer\Mailer($transport); } $mailer->send($email); } protected function buildOAuthMailer(): \Symfony\Component\Mailer\Mailer { $token = $this->resolveOAuthToken(); $username = $this->smtp_username ?? $this->email_address; $host = $this->smtp_host ?? 'smtp.gmail.com'; $port = $this->smtp_port ?? 587; $transport = new \Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport($host, $port, true); $transport->setUsername($username); $transport->setPassword($token); $transport->setAuthenticators([ new \Symfony\Component\Mailer\Transport\Smtp\Auth\XOAuth2Authenticator(), ]); return new \Symfony\Component\Mailer\Mailer($transport); } public function sendReport(string $subject, string $body): bool { if (empty($this->verify_email)) { return false; } try { $this->sendEmail($this->verify_email, $subject, $body); return true; } catch (\Exception $e) { \Illuminate\Support\Facades\Log::error('Sender report email failed', [ 'sender' => $this->email_address, 'error' => $e->getMessage(), ]); return false; } } }