Give mail delivery its own admin page and move the origin probe off /.well-known

The mail page under System tries SMTP, PHP mail() and both sendmail
modes one by one or all at once, and saves the chosen way to .env
without ever showing the password. IONOS answers everything under
/.well-known/ itself with 403, so the address and HTTPS checks never
reached the installation; the probe now lives at /kantsites-origin
(ADR 122).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
kantarciandClaude Opus 5.5 committed 2026-10-12 21:07:27 +02:00
1 parent 2497b8cb69
commit b982cb8944
17 files changed
+597 -148

No files matched your search

+63 -1
View File
@@ -62,7 +62,7 @@ final class MailCheckTest extends TestCase
self::assertSame(['art' => 'SMTP', 'ziel' => 'smtp.ionos.de:587', 'benutzer' => 'formular@kant-it.de', 'gueltig' => true], $route);
self::assertFalse((new MailCheck($this->transport(null), 'kein dsn', $this->log))->route()['gueltig']);
self::assertSame('sendmail des Servers', (new MailCheck($this->transport(null), 'sendmail://default', $this->log))->route()['art']);
self::assertSame('sendmail -bs des Servers', (new MailCheck($this->transport(null), 'sendmail://default', $this->log))->route()['art']);
}
public function testAnAcceptedMailIsLoggedWithWhatToCheckIfNothingArrives(): void
@@ -84,6 +84,68 @@ final class MailCheckTest extends TestCase
self::assertStringContainsString('null://null', MailCheck::hinweisNachErfolg('null'));
}
public function testSmtpSettingsBecomeADsnWithTheSecretsEncoded(): void
{
self::assertSame('smtp://formular%40kant-it.de:a%23b%2Fc%25d%24e@smtp.ionos.de:587', MailCheck::smtpDsn(' SMTP.ionos.de ', 587, 'formular@kant-it.de', 'a#b/c%d$e'));
self::assertSame('smtps://u:p@mail.example.de:465', MailCheck::smtpDsn('mail.example.de', 465, 'u', 'p'));
self::assertSame('smtp://localhost:25', MailCheck::smtpDsn('localhost', 25, '', ''));
foreach ([['smtp.ionos.de/../x', 587], ['', 587], ['smtp.ionos.de', 0]] as [$server, $port]) {
try {
MailCheck::smtpDsn($server, $port, 'u', 'p');
self::fail($server.':'.$port.' hätte abgelehnt werden müssen.');
} catch (\InvalidArgumentException) {
self::addToAssertionCount(1);
}
}
}
public function testTheCurrentSettingFillsTheFormButKeepsThePasswordToItself(): void
{
$mail = new MailCheck($this->transport(null), 'smtp://formular%40kant-it.de:Geheim123@smtp.ionos.de:587', $this->log);
self::assertSame(['weg' => 'smtp', 'server' => 'smtp.ionos.de', 'port' => 587, 'benutzer' => 'formular@kant-it.de', 'passwort' => true], $mail->einstellung());
self::assertSame('Geheim123', $mail->gespeichertesPasswort('smtp.ionos.de', 'formular@kant-it.de'));
// Anderer Server oder Benutzer: das gespeicherte Passwort gilt nicht mit.
self::assertSame('', $mail->gespeichertesPasswort('smtp.office365.com', 'formular@kant-it.de'));
self::assertSame('', $mail->gespeichertesPasswort('smtp.ionos.de', 'jemand@kant-it.de'));
self::assertSame('native', (new MailCheck($this->transport(null), 'native://default', $this->log))->einstellung()['weg']);
self::assertSame('sendmail-t', (new MailCheck($this->transport(null), MailCheck::serverWege()['sendmail-t']['dsn'], $this->log))->einstellung()['weg']);
}
public function testAWayCanBeTriedWithoutBeingTheSetOne(): void
{
// IONOS am 12.10.2026: sendmail -bs bricht ab, mail() geht. Ausprobiert wird über die
// Fabrik, ohne die Einstellung zu ändern.
$versucht = [];
$fabrik = function (string $dsn) use (&$versucht): TransportInterface {
$versucht[] = $dsn;
return $this->transport(null);
};
$eingestellt = $this->transport(new TransportException('Connection to "process /usr/sbin/sendmail -bs" has been closed unexpectedly.'));
$mail = new MailCheck($eingestellt, 'sendmail://default', $this->log, $fabrik);
$ergebnisse = [];
foreach (MailCheck::serverWege() as $schluessel => $weg) {
$ergebnisse[$schluessel] = $mail->send($this->email(), 'Testmail (alle Wege)', $weg['dsn']);
}
self::assertTrue($ergebnisse['native']['ok']);
self::assertSame('PHP mail() des Servers', $ergebnisse['native']['weg']);
self::assertSame('sendmail -t des Servers', $ergebnisse['sendmail-t']['weg']);
self::assertFalse($ergebnisse['sendmail-bs']['ok']);
self::assertStringContainsString('PHP mail()', $ergebnisse['sendmail-bs']['hinweis']);
// Der eingestellte Weg (hier sendmail -bs) geht über den Transport des Frameworks, nicht die Fabrik.
self::assertSame(['native://default', MailCheck::serverWege()['sendmail-t']['dsn']], $versucht);
self::assertCount(3, $mail->recent());
}
public function testAForeignSenderGetsItsOwnHint(): void
{
$meldung = 'Process failed with exit code 65: sendmail: envelope from address kantarci.u@gmail.com not accepted by the server sendmail: server message: 550-Sender address is not allowed.';
self::assertStringContainsString('eigenen Domain beim Hoster', MailCheck::hinweis($meldung, 'native'));
}
private function email(): Email
{
return (new Email())->from('formular@kant-it.de')->to('info@huefner-gartenbau.de')->subject('Anfrage')->text('Test');