denyAccessUnlessGranted('ROLE_ADMIN'); $session = $request->getSession(); return $this->render('admin/mail.html.twig', [ 'mail' => $this->mailFacts(), 'mailResult' => $session->remove('mail_result'), 'mailResults' => $session->remove('mail_results'), 'mailNotice' => $session->remove('mail_notice'), // Die letzte Eingabe bleibt stehen, ohne Passwort. 'mailForm' => $session->remove('mail_form'), ]); } /** * Versand einstellen und ausprobieren (ADR 121, 122): ein Weg testen, alle Wege des Servers * nacheinander testen, oder den gewählten Weg als MAILER_DSN in .env speichern. * * Das SMTP-Passwort steht nie im Formular. Bleibt das Feld leer, gilt das gespeicherte, solange * Server und Benutzer gleich bleiben. */ #[Route('/%kant.admin_path%/system/e-mail', name: 'admin_mail_save', methods: ['POST'])] public function save(Request $request): Response { $this->denyAccessUnlessGranted('ROLE_ADMIN'); $session = $request->getSession(); if (!$this->isCsrfTokenValid('system', $request->request->getString('_csrf_token'))) { return $this->backToMail($request, 'Deine Sitzung ist abgelaufen. Bitte melde dich erneut an.'); } $eingabe = [ 'weg' => $request->request->getString('weg'), 'server' => trim($request->request->getString('server')), 'port' => $request->request->getInt('port', 587), 'benutzer' => trim($request->request->getString('benutzer')), 'an' => trim($request->request->getString('to')), 'von' => trim($request->request->getString('from')), ]; $session->set('mail_form', $eingabe); $aktion = $request->request->getString('aktion'); if ('alle' === $aktion) { if (null !== $fehler = $this->mailAdressFehler($eingabe)) { return $this->backToMail($request, $fehler); } $wege = array_map(static fn (array $weg): string => $weg['dsn'], MailCheck::serverWege()); if ('' !== $eingabe['server']) { try { $wege['smtp'] = $this->smtpDsn($request, $eingabe); } catch (\InvalidArgumentException) { // Unvollständiges SMTP bleibt bei „alle“ einfach draußen. } } $ergebnisse = []; foreach ($wege as $schluessel => $dsn) { $ergebnisse[] = ['schluessel' => $schluessel] + $this->mail->send($this->testEmail($request, $eingabe), 'Testmail (alle Wege)', $dsn); } $session->set('mail_results', $ergebnisse); return $this->backToMail($request); } try { $dsn = isset(MailCheck::serverWege()[$eingabe['weg']]) ? MailCheck::serverWege()[$eingabe['weg']]['dsn'] : $this->smtpDsn($request, $eingabe); } catch (\InvalidArgumentException $fehler) { return $this->backToMail($request, $fehler->getMessage()); } if ('speichern' === $aktion) { if ('.env' !== $this->environmentSource('MAILER_DSN')) { return $this->backToMail($request, 'MAILER_DSN ist in der Server-Umgebung gesetzt und hat dort Vorrang. Ändern lässt sie sich nur beim Hoster.'); } try { Environment::write($this->projectDir, ['MAILER_DSN' => $dsn]); } catch (\RuntimeException $fehler) { return $this->backToMail($request, $fehler->getMessage()); } $weg = $this->mail->route($dsn); return $this->backToMail($request, sprintf('Gespeichert: %s%s. Formulare versenden ab jetzt auf diesem Weg.', $weg['art'], '' !== $weg['ziel'] ? ' über '.$weg['ziel'] : ''), 'ok'); } if (null !== $fehler = $this->mailAdressFehler($eingabe)) { return $this->backToMail($request, $fehler); } $session->set('mail_result', ['an' => $eingabe['an']] + $this->mail->send($this->testEmail($request, $eingabe), 'Testmail', $dsn)); return $this->backToMail($request); } /** „Letzte Versuche“ leeren: var/log/mail.log und mail.log.1. */ #[Route('/%kant.admin_path%/system/e-mail/protokoll', name: 'admin_mail_clear', methods: ['POST'])] public function clear(Request $request): Response { $this->denyAccessUnlessGranted('ROLE_ADMIN'); if (!$this->isCsrfTokenValid('system', $request->request->getString('_csrf_token'))) { return $this->backToMail($request, 'Deine Sitzung ist abgelaufen. Bitte melde dich erneut an.'); } $this->mail->clearLog(); return $this->backToMail($request, 'Das Protokoll ist leer.', 'ok'); } /** @param array{an: string, von: string} $eingabe */ private function mailAdressFehler(array $eingabe): ?string { foreach ([$eingabe['an'], $eingabe['von'] ?: $eingabe['an']] as $adresse) { if (false === filter_var($adresse, FILTER_VALIDATE_EMAIL)) { return '' === $adresse ? 'Für eine Testmail bitte eine Empfängeradresse eintragen.' : sprintf('„%s“ ist keine gültige E-Mail-Adresse.', mb_substr($adresse, 0, 100)); } } return null; } /** @param array{server: string, port: int, benutzer: string} $eingabe */ private function smtpDsn(Request $request, array $eingabe): string { if ('' === $eingabe['server']) { throw new \InvalidArgumentException('Für SMTP bitte den Server eintragen, etwa smtp.ionos.de.'); } $passwort = $request->request->getString('passwort'); if ('' === $passwort) { $passwort = $this->mail->gespeichertesPasswort($eingabe['server'], $eingabe['benutzer']); } if ('' !== $eingabe['benutzer'] && '' === $passwort) { throw new \InvalidArgumentException('Für SMTP bitte das Passwort des Postfachs eintragen.'); } return MailCheck::smtpDsn($eingabe['server'], $eingabe['port'], $eingabe['benutzer'], $passwort); } /** @param array{an: string, von: string} $eingabe */ private function testEmail(Request $request, array $eingabe): Email { $website = rtrim($this->siteOrigin, '/') ?: $request->getSchemeAndHttpHost(); return (new Email()) ->from(new Address($eingabe['von'] ?: $eingabe['an'])) ->to(new Address($eingabe['an'])) ->subject('Testmail von '.(parse_url($website, PHP_URL_HOST) ?: $website)) ->text("Diese Testmail kommt aus der Verwaltung von {$website} (System → E-Mail-Versand).\n\nWenn sie angekommen ist, funktioniert der Versand der Formulare auf diesem Weg.\n"); } private function backToMail(Request $request, ?string $meldung = null, string $art = 'error'): Response { if (null !== $meldung) { $request->getSession()->set('mail_notice', ['art' => $art, 'text' => $meldung]); } return $this->redirect($this->generateUrl('admin_mail')); } /** @return array */ private function mailFacts(): array { $route = $this->mail->route(); return $route + [ 'einstellung' => $this->mail->einstellung(), 'wege' => MailCheck::serverWege(), 'quelle' => $this->environmentSource('MAILER_DSN'), // Wer sich mit einer Adresse anmeldet, versendet meist auch nur unter ihr. 'absender' => false !== filter_var($route['benutzer'], FILTER_VALIDATE_EMAIL) ? $route['benutzer'] : '', 'protokoll' => $this->mail->recent(), ]; } /** Explicit server values take precedence over the single installation file. */ private function environmentSource(string $name): string { $loaded = explode(',', $_SERVER['SYMFONY_DOTENV_VARS'] ?? $_ENV['SYMFONY_DOTENV_VARS'] ?? ''); return in_array($name, $loaded, true) ? '.env' : 'Server-Umgebung'; } }