renderTemplate($template, $vars, $locale); return $this->send($to, $subject, $html, $text, [ 'template' => $template, ]); } public function send( string $to, string $subject, string $html, string $text, array $meta = [] ): array { $logId = $this->mailLogRepository->create([ 'to_email' => $to, 'subject' => $subject, 'template' => $meta['template'] ?? null, 'status' => 'queued', ]); if (!class_exists(PHPMailer::class)) { if ($logId) { $this->mailLogRepository->markFailed($logId, 'PHPMailer is not installed'); } return ['ok' => false, 'error' => 'mailer_missing']; } try { $mailer = $this->createMailer(); $mailer->addAddress($to); $mailer->Subject = $subject; $mailer->Body = $html; $mailer->AltBody = $text; $mailer->isHTML(true); $mailer->send(); if ($logId) { $this->mailLogRepository->markSent($logId, $mailer->getLastMessageID() ?: null); } return ['ok' => true]; } catch (MailerException $e) { if ($logId) { $this->mailLogRepository->markFailed($logId, $e->getMessage()); } return ['ok' => false, 'error' => 'send_failed']; } } private function renderTemplate(string $template, array $vars, string $locale): array { $base = dirname(__DIR__, 3) . '/templates/emails'; $htmlPath = $base . '/' . $locale . '/' . $template . '.html'; $textPath = $base . '/' . $locale . '/' . $template . '.txt'; $htmlHeaderPath = $base . '/' . $locale . '/partials/header.html'; $htmlFooterPath = $base . '/' . $locale . '/partials/footer.html'; $textHeaderPath = $base . '/' . $locale . '/partials/header.txt'; $textFooterPath = $base . '/' . $locale . '/partials/footer.txt'; if (!is_file($htmlPath)) { $htmlPath = $base . '/' . $template . '.html'; } if (!is_file($textPath)) { $textPath = $base . '/' . $template . '.txt'; } if (!is_file($htmlHeaderPath)) { $htmlHeaderPath = $base . '/partials/header.html'; } if (!is_file($htmlFooterPath)) { $htmlFooterPath = $base . '/partials/footer.html'; } if (!is_file($textHeaderPath)) { $textHeaderPath = $base . '/partials/header.txt'; } if (!is_file($textFooterPath)) { $textFooterPath = $base . '/partials/footer.txt'; } $html = is_file($htmlPath) ? file_get_contents($htmlPath) : ''; $text = is_file($textPath) ? file_get_contents($textPath) : ''; if (!isset($vars['email_header'])) { $vars['email_header'] = is_file($htmlHeaderPath) ? file_get_contents($htmlHeaderPath) : ''; } if (!isset($vars['email_footer'])) { $vars['email_footer'] = is_file($htmlFooterPath) ? file_get_contents($htmlFooterPath) : ''; } if (!isset($vars['email_header_text'])) { $vars['email_header_text'] = is_file($textHeaderPath) ? file_get_contents($textHeaderPath) : ''; } if (!isset($vars['email_footer_text'])) { $vars['email_footer_text'] = is_file($textFooterPath) ? file_get_contents($textFooterPath) : ''; } foreach ($vars as $key => $value) { $placeholder = '{{' . $key . '}}'; $html = str_replace($placeholder, (string) $value, $html); $text = str_replace($placeholder, (string) $value, $text); } // Second pass to resolve placeholders inside injected header/footer content. foreach ($vars as $key => $value) { $placeholder = '{{' . $key . '}}'; $html = str_replace($placeholder, (string) $value, $html); $text = str_replace($placeholder, (string) $value, $text); } return [$html, $text]; } private function createMailer(): PHPMailer { $mailer = new PHPMailer(true); $mailer->isSMTP(); $host = $this->settingGateway->getSmtpHost() ?? (getenv('SMTP_HOST') ?: ''); $port = $this->settingGateway->getSmtpPort() ?? (int) (getenv('SMTP_PORT') ?: 587); $user = $this->settingGateway->getSmtpUser() ?? (getenv('SMTP_USER') ?: ''); $pass = $this->settingGateway->getSmtpPassword() ?? (getenv('SMTP_PASS') ?: ''); $secure = $this->settingGateway->getSmtpSecure() ?? strtolower((string) (getenv('SMTP_SECURE') ?: 'tls')); $from = $this->settingGateway->getSmtpFrom() ?? (getenv('SMTP_FROM') ?: ($user ?: 'no-reply@localhost')); $fromName = $this->settingGateway->getSmtpFromName() ?? (getenv('SMTP_FROM_NAME') ?: appTitle()); $mailer->Host = $host; $mailer->Port = $port; $mailer->SMTPAuth = $user !== '' || $pass !== ''; $mailer->Username = $user; $mailer->Password = $pass; if (in_array($secure, ['tls', 'ssl'], true)) { $mailer->SMTPSecure = $secure; } $mailer->setFrom($from, $fromName); $mailer->CharSet = 'UTF-8'; return $mailer; } }