mailFactory = $mailFactory ?? app(MailFactory::class); } public function forTenant(string $tenantCode): self { parent::forTenant($tenantCode); if ($this->clientIntegration) { $this->mailer = $this->resolveMailer(); $this->usesClientMailer = true; } else { $this->mailer = $this->mailFactory->mailer(); $this->usesClientMailer = false; } return $this; } public function forClient(Client|string $client): self { parent::forClient($client); $this->tenant = $this->clientContext?->tenants()->first(); if ($this->clientIntegration) { $this->mailer = $this->resolveMailer(); $this->usesClientMailer = true; } else { $this->mailer = $this->mailFactory->mailer(); $this->usesClientMailer = false; } return $this; } public function getHeaders(): array { return []; } /** * @param array $attachments */ public function send( string|array $recipient, string $subject, string $content, Tenant|WebsiteType|null $brand = null, array $attachments = [], ): void { if (! $this->mailer || ! $this->tenant) { throw new Exception('MailService no está configurado. Llamá a forTenant() o forClient() primero.'); } $brand ??= $this->tenant; $branding = $this->brandingFor($brand); $html = Blade::render( <<<'BLADE' {!! $content !!} BLADE, [ 'branding' => $branding, 'headerLogoUrl' => $brand instanceof WebsiteType ? $brand->siteLogo?->getTemporaryUrl(1440) : $brand->headerLogo?->getTemporaryUrl(1440), 'footerLogoUrl' => $brand->footerLogo?->getTemporaryUrl(1440), 'content' => $content, ], ); $mail = (new Mailable) ->subject($subject) ->html($html); foreach ($attachments as $attachment) { $mail->attachData( $attachment['data'], $attachment['name'], ['mime' => $attachment['mime']], ); } $this->mailer->to($recipient)->send($mail); } public function mailerName(): string { return $this->usesClientMailer ? 'client-smtp' : (string) config('mail.default'); } /** @return array{name: string, primary_color: string, body_color: string, background_color: string, surface_color: string, header_bg_color: string, footer_bg_color: string} */ private function brandingFor(Tenant|WebsiteType $brand): array { if ($brand instanceof WebsiteType) { $brand->loadMissing(['siteLogo', 'footerLogo']); return [ 'name' => $brand->nombre, 'primary_color' => $brand->primary_color ?? '#FF7006', 'body_color' => $brand->body_color ?? '#666666', 'background_color' => $brand->background_color ?? '#f8f8f8', 'surface_color' => $brand->surface_color ?? '#ffffff', 'header_bg_color' => $brand->surface_color ?? '#ffffff', 'footer_bg_color' => $brand->login_header_footer_color ?? '#838383', ]; } $brand->loadMissing(['headerLogo', 'footerLogo']); return [ 'name' => $brand->nombre, 'primary_color' => $brand->primary_color ?? '#6376f3', 'body_color' => '#334155', 'background_color' => '#f1f5f9', 'surface_color' => '#ffffff', 'header_bg_color' => $brand->header_bg_color ?? '#ffffff', 'footer_bg_color' => $brand->footer_bg_color ?? '#334155', ]; } public function onSetup(): void { if (! $this->mailer || ! $this->clientContext) { throw new Exception('MailService no está configurado. Llamá a forTenant() o forClient() primero.'); } $recipient = $this->getIntegrationSetting('MAIL_FROM_ADDRESS'); if (! is_string($recipient) || $recipient === '') { throw new InvalidArgumentException('Falta MAIL_FROM_ADDRESS en la configuración SMTP del cliente.'); } $subject = 'Configuración de correo validada'; $content = '

Configuración de correo validada

' .'

La integración SMTP de '.e($this->clientContext->name).' fue configurada correctamente.

' .'

Este mensaje fue enviado automáticamente para validar las credenciales de correo.

'; if ($this->tenant) { $this->send($recipient, $subject, $content); return; } $this->mailer->to($recipient)->send( (new Mailable)->subject($subject)->html($content) ); } private function resolveMailer(): Mailer { $data = $this->clientIntegration?->integration_data; if (! is_array($data)) { throw new InvalidArgumentException('La configuración SMTP del cliente no es válida.'); } foreach (self::REQUIRED_SMTP_FIELDS as $field) { if (! array_key_exists($field, $data) || $data[$field] === null || $data[$field] === '') { throw new InvalidArgumentException("Falta {$field} en la configuración SMTP del cliente."); } } // MailFake implements MailFactory but cannot build transports. if (! $this->mailFactory instanceof MailManager) { return $this->mailFactory->mailer(); } $mailer = $this->mailFactory->build([ 'name' => 'client-smtp-'.$this->clientContext?->id, 'transport' => 'smtp', 'scheme' => $data['MAIL_SCHEME'] ?? null, 'host' => $data['MAIL_HOST'], 'port' => (int) $data['MAIL_PORT'], 'username' => $data['MAIL_USERNAME'], 'password' => $data['MAIL_PASSWORD'], 'timeout' => isset($data['MAIL_TIMEOUT']) ? (int) $data['MAIL_TIMEOUT'] : null, 'local_domain' => $data['MAIL_EHLO_DOMAIN'] ?? null, ]); $mailer->alwaysFrom( $data['MAIL_FROM_ADDRESS'], $data['MAIL_FROM_NAME'] ?? $this->clientContext?->name, ); return $mailer; } }