This commit is contained in:
2025-12-28 02:02:27 +01:00
parent b753b96747
commit b3e39ea10d

View File

@@ -6,6 +6,7 @@ namespace App;
final class Mailer
{
private string $logFile;
private bool $logCleared = false;
public function __construct(private App $app)
{
@@ -27,6 +28,11 @@ final class Mailer
if (!is_dir($dir)) {
@mkdir($dir, 0775, true);
}
// For clarity keep only the latest run in the log: truncate once per request
if ($this->logCleared === false) {
@file_put_contents($this->logFile, '');
$this->logCleared = true;
}
@file_put_contents($this->logFile, $line, FILE_APPEND);
}
@@ -95,6 +101,7 @@ final class Mailer
if (is_array($decoded) && !empty($decoded['ok']) && !empty($decoded['html'])) {
$this->log('template_api_success', ['template' => $id, 'subject' => $decoded['subject'] ?? null, 'html_len' => strlen((string)$decoded['html'])]);
return [
'id' => $id,
'subject' => $decoded['subject'] ?? 'Papa-Kind-Treff',
'html' => $decoded['html'],
];
@@ -113,6 +120,7 @@ final class Mailer
}
$this->log('template_fallback_used', ['template' => $id]);
return [
'id' => $id,
'subject' => $subject,
'html' => nl2br(htmlspecialchars($body, ENT_QUOTES)),
];
@@ -125,6 +133,7 @@ final class Mailer
}
$tpl = $this->renderTemplate($templateKey, $vars);
$resolvedId = $tpl['id'] ?? $templateKey;
$subject = $tpl['subject'] ?? 'Papa-Kind-Treff';
$html = $tpl['html'] ?? '';
@@ -132,7 +141,13 @@ final class Mailer
$fromEmail = getenv('MAIL_FROM') ?: 'no-reply@' . $this->app->config()->primaryDomain;
$fromName = getenv('MAIL_FROM_NAME') ?: 'Papa-Kind-Treff';
$this->log('mail_send_start', ['template' => $templateKey, 'to' => $to, 'transport' => $transport, 'subject' => $subject]);
$this->log('mail_send_start', [
'template_key' => $templateKey,
'template_id' => $resolvedId,
'to' => $to,
'transport' => $transport,
'subject' => $subject
]);
if ($transport === 'smtp') {
$this->sendSmtp($to, $subject, $html, $fromEmail, $fromName);
} else {
@@ -163,6 +178,7 @@ final class Mailer
$secure = strtolower(getenv('SMTP_SECURE') ?: 'tls'); // tls|ssl|none
if (!$host) {
$this->log('mail_smtp_missing_host_fallback_mail', []);
$this->sendMailFn($to, $subject, $html, $from, $fromName);
return;
}
@@ -176,10 +192,16 @@ final class Mailer
}
stream_set_timeout($fp, 15);
$read = function () use ($fp) {
return fgets($fp, 515);
$transcript = [];
$read = function (string $label = 'read') use ($fp, &$transcript) {
$line = fgets($fp, 515);
if ($line !== false) {
$transcript[] = $label . ': ' . trim($line);
}
return $line;
};
$write = function (string $cmd) use ($fp) {
$write = function (string $cmd, string $label = 'write', bool $mask = false) use ($fp, &$transcript) {
$transcript[] = $label . ': ' . ($mask ? '[omitted]' : $cmd);
fwrite($fp, $cmd . "\r\n");
};
@@ -192,6 +214,8 @@ final class Mailer
$read();
if (!stream_socket_enable_crypto($fp, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) {
fclose($fp);
$this->log('mail_smtp_starttls_failed', ['host' => $host, 'port' => $port]);
$this->log('mail_smtp_transcript', ['host' => $host, 'port' => $port, 'secure' => $secure, 'steps' => $transcript]);
$this->sendMailFn($to, $subject, $html, $from, $fromName);
return;
}
@@ -202,9 +226,9 @@ final class Mailer
if ($user !== '') {
$write('AUTH LOGIN');
$read();
$write(base64_encode($user));
$write(base64_encode($user), 'auth-user', true);
$read();
$write(base64_encode($pass));
$write(base64_encode($pass), 'auth-pass', true);
$read();
}
@@ -221,10 +245,18 @@ final class Mailer
$msg .= "MIME-Version: 1.0\r\n";
$msg .= "Content-Type: text/html; charset=utf-8\r\n\r\n";
$msg .= $html . "\r\n.\r\n";
$write($msg);
$read();
$write($msg, 'data');
$resp = $read('data-response');
$write('QUIT');
fclose($fp);
$this->log('mail_smtp_transcript', ['host' => $host, 'port' => $port, 'secure' => $secure, 'steps' => $transcript]);
if ($resp === false || !str_starts_with((string)$resp, '250')) {
$this->log('mail_smtp_send_failed', ['host' => $host, 'port' => $port, 'resp' => $resp]);
$this->sendMailFn($to, $subject, $html, $from, $fromName);
return;
}
$this->log('mail_smtp_sent', ['to' => $to, 'host' => $host, 'port' => $port, 'secure' => $secure]);
}
}