_PhilippUrbschat

Hallo,

du wurdest eingeladen, dir einen persönlichen Zugang auf philippurbschat.de anzulegen.

' . (!empty($note) ? '
' . htmlspecialchars($note) . '
' : '') . '
Freigeschaltete Module:
' . htmlspecialchars($modulesText) . '
Jetzt Account erstellen →

Falls der Button nicht funktioniert, kopiere bitte diesen Link in deinen Browser:
' . htmlspecialchars($registerUrl) . '

philippurbschat.de · Leopoldstr. 32 · 32756 Detmold
'; $bodyText = "Hallo,\n\n" . "du wurdest eingeladen, dir einen persönlichen Zugang auf philippurbschat.de anzulegen.\n\n" . (!empty($note) ? "Hinweis: {$note}\n\n" : "") . "Freigeschaltete Systeme: {$modulesText}\n\n" . "Öffne folgenden Link, um dein Konto zu erstellen:\n" . $registerUrl . "\n\n" . "Viele Grüße,\nPhilipp Urbschat"; return self::send($toEmail, $subject, $bodyHtml, $bodyText); } /** * Send a password reset email */ public static function sendPasswordReset(string $toEmail, string $token): bool { $baseUrl = self::getBaseUrl(); $resetUrl = $baseUrl . 'reset-password?token=' . urlencode($token); $subject = 'Passwort zurücksetzen – philippurbschat.de'; $bodyHtml = '
_Passwort-Reset

Hallo,

wir haben eine Anfrage zum Zurücksetzen deines Passworts auf philippurbschat.de erhalten.

Neues Passwort vergeben →

Dieser Link ist aus Sicherheitsgründen 1 Stunde lang gültig.

Falls der Button nicht funktioniert, nutze bitte diesen Link:
' . htmlspecialchars($resetUrl) . '

Wenn du diesen Reset nicht angefordert hast, kannst du diese Nachricht einfach ignorieren. Dein bisheriges Passwort bleibt unverändert gültig.

philippurbschat.de · Leopoldstr. 32 · 32756 Detmold
'; $bodyText = "Hallo,\n\n" . "wir haben eine Anfrage zum Zurücksetzen deines Passworts auf philippurbschat.de erhalten.\n\n" . "Klicke auf den folgenden Link, um ein neues Passwort festzulegen (1 Stunde gültig):\n" . $resetUrl . "\n\n" . "Falls du diesen Reset nicht angefordert hast, kannst du diese Nachricht ignorieren.\n\n" . "Viele Grüße,\nPhilipp Urbschat"; return self::send($toEmail, $subject, $bodyHtml, $bodyText); } /** * Internal mail dispatcher */ private static function send(string $to, string $subject, string $htmlBody, string $textBody): bool { $fromEmail = self::getFromEmail(); $fromName = self::getFromName(); // 1. Always log locally for auditing & development self::logEmail($to, $subject, $textBody); // 2. Try SMTP if credentials exist $smtpHost = Config::get('SMTP_HOST'); if (!empty($smtpHost)) { try { return self::sendViaSmtp($to, $subject, $htmlBody, $textBody); } catch (Exception $e) { error_log("MailService SMTP Error: " . $e->getMessage()); } } // 3. Fallback to PHP native mail() $boundary = "==Multipart_Boundary_x" . md5(uniqid(time())); $encodedSubject = '=?UTF-8?B?' . base64_encode($subject) . '?='; $encodedFromName = '=?UTF-8?B?' . base64_encode($fromName) . '?='; $headers = []; $headers[] = "MIME-Version: 1.0"; $headers[] = "From: {$encodedFromName} <{$fromEmail}>"; $headers[] = "Reply-To: {$fromEmail}"; $headers[] = "Content-Type: multipart/alternative; boundary=\"{$boundary}\""; $headers[] = "X-Mailer: PhilippUrbschat-Mailer/1.0"; $message = "--{$boundary}\r\n"; $message .= "Content-Type: text/plain; charset=UTF-8\r\n"; $message .= "Content-Transfer-Encoding: base64\r\n\r\n"; $message .= chunk_split(base64_encode($textBody)) . "\r\n"; $message .= "--{$boundary}\r\n"; $message .= "Content-Type: text/html; charset=UTF-8\r\n"; $message .= "Content-Transfer-Encoding: base64\r\n\r\n"; $message .= chunk_split(base64_encode($htmlBody)) . "\r\n"; $message .= "--{$boundary}--\r\n"; $headerStr = implode("\r\n", $headers); $additionalParams = "-f " . escapeshellarg($fromEmail); $sent = @mail($to, $encodedSubject, $message, $headerStr, $additionalParams); if (!$sent) { error_log("MailService: mail() returned false. Email was logged to data/mail_log.txt"); } return true; } private static function logEmail(string $to, string $subject, string $body): void { $logDir = __DIR__ . '/../../data'; if (!is_dir($logDir)) { @mkdir($logDir, 0775, true); } $logFile = $logDir . '/mail_log.txt'; $timestamp = date('Y-m-d H:i:s'); $logEntry = str_repeat('=', 60) . "\n" . "TIMESTAMP: {$timestamp}\n" . "TO: {$to}\n" . "SUBJECT: {$subject}\n" . "BODY:\n{$body}\n\n"; @file_put_contents($logFile, $logEntry, FILE_APPEND); } private static function sendViaSmtp(string $to, string $subject, string $htmlBody, string $textBody): bool { $host = Config::get('SMTP_HOST'); $port = (int)Config::get('SMTP_PORT', 587); $user = Config::get('SMTP_USER'); $pass = Config::get('SMTP_PASS'); $from = self::getFromEmail(); $fromName = self::getFromName(); $socket = @fsockopen(($port === 465 ? 'ssl://' : '') . $host, $port, $errno, $errstr, 10); if (!$socket) { throw new Exception("Socket connection failed: {$errstr} ({$errno})"); } $getResponse = function() use ($socket) { $response = ''; while ($str = fgets($socket, 515)) { $response .= $str; if (substr($str, 3, 1) === ' ') break; } return $response; }; $sendCommand = function($cmd) use ($socket, $getResponse) { fputs($socket, $cmd . "\r\n"); return $getResponse(); }; $getResponse(); // Read greeting $sendCommand("EHLO " . gethostname()); if ($port === 587) { $tlsRes = $sendCommand("STARTTLS"); if (strpos($tlsRes, '220') === 0) { stream_socket_enable_crypto($socket, true, STREAM_CRYPTO_METHOD_TLS_CLIENT); $sendCommand("EHLO " . gethostname()); } } if (!empty($user) && !empty($pass)) { $sendCommand("AUTH LOGIN"); $sendCommand(base64_encode($user)); $sendCommand(base64_encode($pass)); } $sendCommand("MAIL FROM: <{$from}>"); $sendCommand("RCPT TO: <{$to}>"); $sendCommand("DATA"); $boundary = "==Multipart_Boundary_x" . md5(uniqid(time())); $encodedSubject = '=?UTF-8?B?' . base64_encode($subject) . '?='; $encodedFromName = '=?UTF-8?B?' . base64_encode($fromName) . '?='; $headers = [ "MIME-Version: 1.0", "From: {$encodedFromName} <{$from}>", "To: {$to}", "Subject: {$encodedSubject}", "Content-Type: multipart/alternative; boundary=\"{$boundary}\"", "X-Mailer: PhilippUrbschat-Mailer/1.0" ]; $content = implode("\r\n", $headers) . "\r\n\r\n"; $content .= "--{$boundary}\r\n"; $content .= "Content-Type: text/plain; charset=UTF-8\r\n"; $content .= "Content-Transfer-Encoding: base64\r\n\r\n"; $content .= chunk_split(base64_encode($textBody)) . "\r\n"; $content .= "--{$boundary}\r\n"; $content .= "Content-Type: text/html; charset=UTF-8\r\n"; $content .= "Content-Transfer-Encoding: base64\r\n\r\n"; $content .= chunk_split(base64_encode($htmlBody)) . "\r\n"; $content .= "--{$boundary}--\r\n."; $sendCommand($content); $sendCommand("QUIT"); fclose($socket); return true; } }