2026-07-05 00:27:19 +02:00
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
declare(strict_types=1);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* SMTP-Verbindungstest — prüft Host, STARTTLS und Login aus config/config.php,
|
|
|
|
|
* OHNE eine E-Mail zu versenden (nur Verbindung + Auth, danach QUIT).
|
|
|
|
|
*
|
|
|
|
|
* NUR CLI — nie im Request-Pfad. Debug-Ausgabe bleibt aus, damit keine
|
|
|
|
|
* Zugangsdaten (Base64 im AUTH-Dialog) im Terminal oder in Logs landen.
|
|
|
|
|
*
|
2026-07-31 17:03:00 +02:00
|
|
|
* Aufruf: php bin/smtp-test.php (Passwort aus config/config.php)
|
|
|
|
|
* php bin/smtp-test.php --frage (Passwort verdeckt eingeben)
|
|
|
|
|
*
|
|
|
|
|
* --frage ist für den Fall, dass das Postfach-Passwort neu gesetzt wurde: erst
|
|
|
|
|
* prüfen, ob es überhaupt trägt, dann in die Config schreiben. Sonst schreibt man
|
|
|
|
|
* einen ungetesteten Wert in eine Datei, die auf zwei Rechnern liegt. Verdeckte
|
|
|
|
|
* Eingabe statt Argument, damit kein Klartext in der Shell-History landet.
|
2026-07-05 00:27:19 +02:00
|
|
|
*/
|
|
|
|
|
if (PHP_SAPI !== 'cli') {
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
require dirname(__DIR__) . '/app/bootstrap.php';
|
|
|
|
|
|
|
|
|
|
use PHPMailer\PHPMailer\PHPMailer;
|
|
|
|
|
|
|
|
|
|
$smtp = config('smtp');
|
2026-07-31 17:03:00 +02:00
|
|
|
$frage = in_array('--frage', $argv, true);
|
|
|
|
|
|
|
|
|
|
if ($frage) {
|
|
|
|
|
echo "Postfach-Passwort für {$smtp['username']} (Eingabe unsichtbar): ";
|
|
|
|
|
system('stty -echo');
|
|
|
|
|
$eingabe = trim((string) fgets(STDIN));
|
|
|
|
|
system('stty echo');
|
|
|
|
|
echo "\n";
|
|
|
|
|
if ($eingabe === '') {
|
|
|
|
|
fwrite(STDERR, "Abbruch: kein Passwort eingegeben.\n");
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
$smtp['password'] = $eingabe;
|
|
|
|
|
}
|
2026-07-05 00:27:19 +02:00
|
|
|
|
|
|
|
|
if (in_array($smtp['password'] ?? '', ['', 'POSTFACH_PASSWORT', 'BREVO_SMTP_KEY', 'CHANGE_ME'], true)) {
|
|
|
|
|
fwrite(STDERR, "Abbruch: In config/config.php steht noch kein echtes SMTP-Passwort.\n");
|
2026-07-31 17:03:00 +02:00
|
|
|
fwrite(STDERR, "Zum Ausprobieren ohne Config-Änderung: php bin/smtp-test.php --frage\n");
|
2026-07-05 00:27:19 +02:00
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-31 17:03:00 +02:00
|
|
|
// --- --probe: mehrere Zugangswege durchprobieren ---
|
|
|
|
|
// Hintergrund (31.07.2026): dieselben Zugangsdaten wurden vom Entwicklungsrechner
|
|
|
|
|
// akzeptiert, vom Webspace aber mit „Could not authenticate" abgelehnt.
|
|
|
|
|
// w01ca75d.kasserver.com und der Webserver zeigen auf dieselbe IP — vom Server aus
|
|
|
|
|
// verbindet sich PHP also mit der eigenen Maschine, und die kann Anmeldungen anders
|
|
|
|
|
// behandeln als von außen. Diese Sonde findet heraus, welcher Weg trägt, statt zu raten.
|
|
|
|
|
// Bewusst nur vier Kombinationen: jeder Fehlversuch ist ein fehlgeschlagener Login,
|
|
|
|
|
// und zu viele davon können ein Postfach vorübergehend sperren.
|
|
|
|
|
if (in_array('--probe', $argv, true)) {
|
|
|
|
|
$wege = [
|
|
|
|
|
['label' => 'Konfiguriert: Host, Port ' . (int) $smtp['port'] . ', STARTTLS, mit Anmeldung',
|
|
|
|
|
'host' => $smtp['host'], 'port' => (int) $smtp['port'], 'sec' => PHPMailer::ENCRYPTION_STARTTLS, 'auth' => true],
|
|
|
|
|
['label' => 'Host, Port 465, SSL, mit Anmeldung',
|
|
|
|
|
'host' => $smtp['host'], 'port' => 465, 'sec' => PHPMailer::ENCRYPTION_SMTPS, 'auth' => true],
|
|
|
|
|
['label' => 'localhost, Port 25, ohne Verschlüsselung, mit Anmeldung',
|
|
|
|
|
'host' => 'localhost', 'port' => 25, 'sec' => '', 'auth' => true],
|
|
|
|
|
['label' => 'localhost, Port 25, ohne Verschlüsselung, OHNE Anmeldung (lokaler Relay)',
|
|
|
|
|
'host' => 'localhost', 'port' => 25, 'sec' => '', 'auth' => false],
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
echo "Sonde: welcher Weg nimmt uns an? Postfach {$smtp['username']}\n\n";
|
|
|
|
|
$erfolg = [];
|
|
|
|
|
foreach ($wege as $i => $weg) {
|
|
|
|
|
$m = new PHPMailer(true);
|
|
|
|
|
$m->isSMTP();
|
|
|
|
|
$m->Host = $weg['host'];
|
|
|
|
|
$m->Port = $weg['port'];
|
|
|
|
|
$m->SMTPAuth = $weg['auth'];
|
|
|
|
|
$m->SMTPSecure = $weg['sec'];
|
|
|
|
|
if (!$weg['auth']) {
|
|
|
|
|
$m->SMTPAutoTLS = false;
|
|
|
|
|
}
|
|
|
|
|
$m->Username = $smtp['username'];
|
|
|
|
|
$m->Password = $smtp['password'];
|
|
|
|
|
$m->Timeout = 12;
|
|
|
|
|
try {
|
|
|
|
|
$ok = $m->smtpConnect();
|
|
|
|
|
$m->smtpClose();
|
|
|
|
|
} catch (Throwable $e) {
|
|
|
|
|
$ok = false;
|
|
|
|
|
$m->ErrorInfo = $e->getMessage();
|
|
|
|
|
}
|
|
|
|
|
printf(" %d. %-68s %s\n", $i + 1, $weg['label'], $ok ? 'GEHT' : 'nein');
|
|
|
|
|
if (!$ok && $m->ErrorInfo !== '') {
|
|
|
|
|
echo ' ' . trim(preg_replace('/\s+/', ' ', $m->ErrorInfo) ?? '') . "\n";
|
|
|
|
|
}
|
|
|
|
|
if ($ok) {
|
|
|
|
|
$erfolg[] = $weg;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
echo "\n";
|
|
|
|
|
if ($erfolg === []) {
|
|
|
|
|
echo "Kein Weg trägt. Dann liegt es am Postfach selbst: Passwort im KAS neu setzen\n";
|
|
|
|
|
echo "und mit php bin/smtp-test.php --frage gegenprüfen.\n";
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
$w = $erfolg[0];
|
|
|
|
|
echo "Nimm den ersten Treffer in config/config.php: host {$w['host']}, port {$w['port']}\n";
|
|
|
|
|
echo 'Verschlüsselung ' . ($w['sec'] === '' ? 'keine' : $w['sec']) . ', Anmeldung ' . ($w['auth'] ? 'ja' : 'nein') . "\n";
|
|
|
|
|
exit(0);
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-05 00:27:19 +02:00
|
|
|
echo "Teste {$smtp['host']}:{$smtp['port']} (STARTTLS) als {$smtp['username']} …\n";
|
|
|
|
|
|
|
|
|
|
$mail = new PHPMailer(true);
|
|
|
|
|
$mail->isSMTP();
|
|
|
|
|
$mail->Host = $smtp['host'];
|
|
|
|
|
$mail->Port = (int) $smtp['port'];
|
|
|
|
|
$mail->SMTPAuth = true;
|
|
|
|
|
$mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
|
|
|
|
|
$mail->Username = $smtp['username'];
|
|
|
|
|
$mail->Password = $smtp['password'];
|
|
|
|
|
$mail->Timeout = 15;
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
if ($mail->smtpConnect()) {
|
|
|
|
|
$mail->smtpClose();
|
|
|
|
|
echo "OK: Verbindung, STARTTLS und Login erfolgreich — keine Mail versendet.\n";
|
2026-07-31 17:03:00 +02:00
|
|
|
if ($frage) {
|
|
|
|
|
echo "Dieses Passwort trägt. Jetzt in config/config.php unter smtp.password eintragen.\n";
|
|
|
|
|
}
|
2026-07-05 00:27:19 +02:00
|
|
|
exit(0);
|
|
|
|
|
}
|
2026-07-31 17:03:00 +02:00
|
|
|
$info = $mail->ErrorInfo !== '' ? $mail->ErrorInfo : 'Verbindung fehlgeschlagen.';
|
|
|
|
|
fwrite(STDERR, 'Fehler: ' . $info . "\n");
|
|
|
|
|
// „Could not authenticate" heißt: Host, Port, Firewall und STARTTLS sind in
|
|
|
|
|
// Ordnung, nur die Zugangsdaten wurden abgelehnt. Das ist die Meldung, die nach
|
|
|
|
|
// einem All-Inkl-Tarifwechsel kam (31.07.2026) — dort mussten die
|
|
|
|
|
// Postfach-Passwörter im KAS neu gesetzt werden.
|
|
|
|
|
if (str_contains($info, 'Could not authenticate')) {
|
|
|
|
|
fwrite(STDERR, "\nDie Verbindung stand, abgelehnt wurde nur die Anmeldung. Prüfe:\n");
|
|
|
|
|
fwrite(STDERR, " 1. Postfach-Passwort im KAS neu setzen (nach einem Tarifwechsel nötig).\n");
|
|
|
|
|
fwrite(STDERR, " 2. Stimmt der Postfachname exakt? Aktuell: {$smtp['username']}\n");
|
|
|
|
|
fwrite(STDERR, " 3. Stimmt der Mailserver? Aktuell: {$smtp['host']} (im KAS unter E-Mail nachsehen).\n");
|
|
|
|
|
fwrite(STDERR, " Neues Passwort ohne Config-Änderung ausprobieren: php bin/smtp-test.php --frage\n");
|
|
|
|
|
}
|
2026-07-05 00:27:19 +02:00
|
|
|
exit(1);
|
|
|
|
|
} catch (Throwable $e) {
|
|
|
|
|
fwrite(STDERR, 'Fehler: ' . $e->getMessage() . "\n");
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|