email setup more functions

This commit is contained in:
2026-02-24 00:02:09 +01:00
parent 401d917a69
commit 2641a13d09
3 changed files with 126 additions and 18 deletions

View File

@@ -71,9 +71,12 @@ require dirname(__DIR__) . '/../structure/layout_start.php';
<fieldset class="border border-slate-200 rounded-xl p-4"> <fieldset class="border border-slate-200 rounded-xl p-4">
<legend class="px-2 text-sm font-semibold">SMTP-Versand</legend> <legend class="px-2 text-sm font-semibold">SMTP-Versand</legend>
<p class="text-xs text-slate-500 mb-3">Diese Zugangsdaten werden fuer den Testversand genutzt, wenn SMTP aktiviert ist.</p> <p class="text-xs text-slate-500 mb-3">Diese Zugangsdaten werden fuer den Testversand genutzt, wenn SMTP aktiviert ist.</p>
<label class="inline-flex items-center gap-2 text-sm text-slate-600 mb-3"> <div class="flex items-center justify-between gap-3 mb-3">
<label class="inline-flex items-center gap-2 text-sm text-slate-600">
<input type="checkbox" name="smtp_enabled" value="1"> SMTP aktivieren <input type="checkbox" name="smtp_enabled" value="1"> SMTP aktivieren
</label> </label>
<button type="button" id="btn-smtp-test" class="btn">SMTP Test</button>
</div>
<div class="grid md:grid-cols-2 gap-3"> <div class="grid md:grid-cols-2 gap-3">
<label class="block text-sm text-slate-600">SMTP-Server <label class="block text-sm text-slate-600">SMTP-Server
<input type="text" name="smtp_host" class="input mt-1" placeholder="smtp.example.com"> <input type="text" name="smtp_host" class="input mt-1" placeholder="smtp.example.com">
@@ -94,6 +97,9 @@ require dirname(__DIR__) . '/../structure/layout_start.php';
<label class="block text-sm text-slate-600">Passwort <label class="block text-sm text-slate-600">Passwort
<input type="password" name="smtp_pass" class="input mt-1" placeholder="••••••••"> <input type="password" name="smtp_pass" class="input mt-1" placeholder="••••••••">
</label> </label>
<label class="inline-flex items-center gap-2 text-xs text-slate-500 mt-6">
<input type="checkbox" name="smtp_pass_clear" value="1"> Passwort loeschen
</label>
<label class="block text-sm text-slate-600">SMTP-Absender (E-Mail) <label class="block text-sm text-slate-600">SMTP-Absender (E-Mail)
<input type="email" name="smtp_from_email" class="input mt-1" placeholder="no-reply@example.com"> <input type="email" name="smtp_from_email" class="input mt-1" placeholder="no-reply@example.com">
</label> </label>

View File

@@ -56,6 +56,7 @@ let adminTablesSelectedSelect;
let adminTablesAddBtn; let adminTablesAddBtn;
let adminTablesRemoveBtn; let adminTablesRemoveBtn;
let adminLoadBridgeBtn; let adminLoadBridgeBtn;
let smtpTestBtn;
ensureConsoleCapture(); ensureConsoleCapture();
@@ -86,6 +87,7 @@ export function initAccountPage() {
adminTablesAddBtn = document.getElementById('adminBridgeTablesAdd'); adminTablesAddBtn = document.getElementById('adminBridgeTablesAdd');
adminTablesRemoveBtn = document.getElementById('adminBridgeTablesRemove'); adminTablesRemoveBtn = document.getElementById('adminBridgeTablesRemove');
adminLoadBridgeBtn = document.getElementById('btn-admin-load-bridge'); adminLoadBridgeBtn = document.getElementById('btn-admin-load-bridge');
smtpTestBtn = document.getElementById('btn-smtp-test');
sectionsList = document.getElementById('sectionsList'); sectionsList = document.getElementById('sectionsList');
sectionsCreateForm = document.getElementById('sectionsCreateForm'); sectionsCreateForm = document.getElementById('sectionsCreateForm');
sectionNameInput = document.getElementById('sectionNameInput'); sectionNameInput = document.getElementById('sectionNameInput');
@@ -140,6 +142,9 @@ export function initAccountPage() {
adminLoadBridgeBtn?.addEventListener('click', () => { adminLoadBridgeBtn?.addEventListener('click', () => {
refreshBridgeTablesFromEndpoint(); refreshBridgeTablesFromEndpoint();
}); });
smtpTestBtn?.addEventListener('click', () => {
runSmtpTest();
});
initSectionsManager(); initSectionsManager();
@@ -452,7 +457,11 @@ function fillSettingsForm(settings) {
if (settingsForm.smtp_host) settingsForm.smtp_host.value = settings.smtp_host || ''; if (settingsForm.smtp_host) settingsForm.smtp_host.value = settings.smtp_host || '';
if (settingsForm.smtp_port) settingsForm.smtp_port.value = settings.smtp_port ? String(settings.smtp_port) : ''; if (settingsForm.smtp_port) settingsForm.smtp_port.value = settings.smtp_port ? String(settings.smtp_port) : '';
if (settingsForm.smtp_user) settingsForm.smtp_user.value = settings.smtp_user || ''; if (settingsForm.smtp_user) settingsForm.smtp_user.value = settings.smtp_user || '';
if (settingsForm.smtp_pass) settingsForm.smtp_pass.value = settings.smtp_pass || ''; if (settingsForm.smtp_pass) settingsForm.smtp_pass.value = '';
if (settingsForm.smtp_pass) {
settingsForm.smtp_pass.placeholder = settings.smtp_pass_set ? 'Passwort gesetzt' : '••••••••';
}
if (settingsForm.smtp_pass_clear) settingsForm.smtp_pass_clear.checked = false;
if (settingsForm.smtp_secure) settingsForm.smtp_secure.value = settings.smtp_secure || ''; if (settingsForm.smtp_secure) settingsForm.smtp_secure.value = settings.smtp_secure || '';
if (settingsForm.smtp_from_email) settingsForm.smtp_from_email.value = settings.smtp_from_email || ''; if (settingsForm.smtp_from_email) settingsForm.smtp_from_email.value = settings.smtp_from_email || '';
if (settingsForm.smtp_from_name) settingsForm.smtp_from_name.value = settings.smtp_from_name || ''; if (settingsForm.smtp_from_name) settingsForm.smtp_from_name.value = settings.smtp_from_name || '';
@@ -518,6 +527,7 @@ async function submitSettingsForm(ev) {
} }
if (settingsForm.smtp_user) data.smtp_user = settingsForm.smtp_user.value.trim(); if (settingsForm.smtp_user) data.smtp_user = settingsForm.smtp_user.value.trim();
if (settingsForm.smtp_pass) data.smtp_pass = settingsForm.smtp_pass.value; if (settingsForm.smtp_pass) data.smtp_pass = settingsForm.smtp_pass.value;
if (settingsForm.smtp_pass_clear) data.smtp_pass_clear = settingsForm.smtp_pass_clear.checked ? 1 : 0;
if (settingsForm.smtp_secure) data.smtp_secure = settingsForm.smtp_secure.value; if (settingsForm.smtp_secure) data.smtp_secure = settingsForm.smtp_secure.value;
if (settingsForm.smtp_from_email) data.smtp_from_email = settingsForm.smtp_from_email.value.trim(); if (settingsForm.smtp_from_email) data.smtp_from_email = settingsForm.smtp_from_email.value.trim();
if (settingsForm.smtp_from_name) data.smtp_from_name = settingsForm.smtp_from_name.value.trim(); if (settingsForm.smtp_from_name) data.smtp_from_name = settingsForm.smtp_from_name.value.trim();
@@ -558,6 +568,31 @@ async function downloadFile(type) {
} }
} }
async function runSmtpTest() {
if (!settingsForm) return;
const recipient = prompt('Test-E-Mail an welche Adresse senden?', window.__currentUser?.email || '');
if (!recipient) return;
const data = {
to: recipient.trim(),
smtp_enabled: settingsForm.smtp_enabled?.checked ? 1 : 0,
smtp_host: settingsForm.smtp_host?.value.trim() || '',
smtp_port: settingsForm.smtp_port?.value.trim() || '',
smtp_user: settingsForm.smtp_user?.value.trim() || '',
smtp_pass: settingsForm.smtp_pass?.value || '',
smtp_secure: settingsForm.smtp_secure?.value || '',
smtp_from_email: settingsForm.smtp_from_email?.value.trim() || '',
smtp_from_name: settingsForm.smtp_from_name?.value.trim() || '',
smtp_reply_to: settingsForm.smtp_reply_to?.value.trim() || '',
};
try {
const res = await apiAction('account.smtp.test', { method: 'POST', data });
if (!res?.ok) throw new Error(res?.error || 'SMTP Test fehlgeschlagen');
toast('SMTP Test gesendet', true);
} catch (err) {
toast(err.message || 'SMTP Test fehlgeschlagen', false);
}
}
function normalizeTableList(input) { function normalizeTableList(input) {
const items = Array.isArray(input) ? input : (typeof input === 'string' ? input.split(/[\s,]+/) : []); const items = Array.isArray(input) ? input : (typeof input === 'string' ? input.split(/[\s,]+/) : []);
const result = []; const result = [];

View File

@@ -2871,21 +2871,22 @@ class ApiKernel
return $map ? strtr($html, $map) : $html; return $map ? strtr($html, $map) : $html;
} }
private function dispatchTestMail(string $to, string $subject, string $html, ?array $sender = null, ?int $customerId = null): bool private function dispatchTestMail(string $to, string $subject, string $html, ?array $sender = null, ?int $customerId = null, ?array $smtpOverride = null): bool
{ {
$this->lastMailError = null; $this->lastMailError = null;
$smtpConf = $this->conf['smtp'] ?? []; $smtpConf = $this->conf['smtp'] ?? [];
$settings = ($customerId && $customerId > 0) ? $this->getCustomerSettings($customerId) : []; $settings = ($customerId && $customerId > 0) ? $this->getCustomerSettings($customerId) : [];
$override = is_array($smtpOverride) ? $smtpOverride : [];
$smtp = array_merge($smtpConf, array_filter([ $smtp = array_merge($smtpConf, array_filter([
'host' => $settings['smtp_host'] ?? null, 'host' => $override['host'] ?? ($settings['smtp_host'] ?? null),
'port' => $settings['smtp_port'] ?? null, 'port' => $override['port'] ?? ($settings['smtp_port'] ?? null),
'user' => $settings['smtp_user'] ?? null, 'user' => $override['user'] ?? ($settings['smtp_user'] ?? null),
'pass' => $settings['smtp_pass'] ?? null, 'pass' => array_key_exists('pass', $override) ? $override['pass'] : ($settings['smtp_pass'] ?? null),
'secure' => $settings['smtp_secure'] ?? null, 'secure' => $override['secure'] ?? ($settings['smtp_secure'] ?? null),
'from_email' => $settings['smtp_from_email'] ?? null, 'from_email' => $override['from_email'] ?? ($settings['smtp_from_email'] ?? null),
'from_name' => $settings['smtp_from_name'] ?? null, 'from_name' => $override['from_name'] ?? ($settings['smtp_from_name'] ?? null),
'reply_to' => $settings['smtp_reply_to'] ?? null, 'reply_to' => $override['reply_to'] ?? ($settings['smtp_reply_to'] ?? null),
'enabled' => $settings['smtp_enabled'] ?? null, 'enabled' => $override['enabled'] ?? ($settings['smtp_enabled'] ?? null),
], static fn($v) => $v !== null && $v !== '')); ], static fn($v) => $v !== null && $v !== ''));
$smtpEnabled = !empty($smtp['enabled']); $smtpEnabled = !empty($smtp['enabled']);
@@ -3074,6 +3075,9 @@ class ApiKernel
case 'account.bridge.test': case 'account.bridge.test':
$this->handleAccountBridgeTest(); $this->handleAccountBridgeTest();
break; break;
case 'account.smtp.test':
$this->handleAccountSmtpTest();
break;
case 'account.fonts.list': case 'account.fonts.list':
$this->handleAccountFontsList(); $this->handleAccountFontsList();
break; break;
@@ -3816,6 +3820,59 @@ class ApiKernel
$this->respond(['ok' => true, 'settings' => $settings]); $this->respond(['ok' => true, 'settings' => $settings]);
} }
private function handleAccountSmtpTest(): void
{
$user = $this->requireAuth();
$this->ensureRole($user, ['owner', 'admin']);
$customerId = (int)($user['customer_id'] ?? 0);
if ($customerId <= 0) $this->fail('Customer context missing', null, 500);
$recipient = trim((string)($this->in['to'] ?? ''));
if ($recipient === '') {
$recipient = (string)($user['email'] ?? '');
}
if ($recipient === '' || !filter_var($recipient, FILTER_VALIDATE_EMAIL)) {
$this->fail('Valid recipient required', null, 422);
}
$smtpOverride = null;
if (array_key_exists('smtp_host', $this->in) || array_key_exists('smtp_enabled', $this->in)) {
$smtpOverride = [
'enabled' => !empty($this->in['smtp_enabled']),
'host' => trim((string)($this->in['smtp_host'] ?? '')),
'port' => (int)($this->in['smtp_port'] ?? 0),
'user' => trim((string)($this->in['smtp_user'] ?? '')),
'pass' => (string)($this->in['smtp_pass'] ?? ''),
'secure' => strtolower(trim((string)($this->in['smtp_secure'] ?? ''))),
'from_email' => trim((string)($this->in['smtp_from_email'] ?? '')),
'from_name' => trim((string)($this->in['smtp_from_name'] ?? '')),
'reply_to' => trim((string)($this->in['smtp_reply_to'] ?? '')),
];
}
$subject = 'EmailTemplate SMTP Test';
$html = '<p>SMTP Test erfolgreich.</p><p>Zeit: ' . date(DATE_ATOM) . '</p>';
$ok = $this->dispatchTestMail($recipient, $subject, $html, null, $customerId, $smtpOverride);
$this->writeDebugLog('smtp_test', [
'time' => date(DATE_ATOM),
'customer_id' => $customerId,
'to' => $recipient,
'smtp_enabled' => $smtpOverride['enabled'] ?? null,
'smtp_host' => $smtpOverride['host'] ?? null,
'smtp_port' => $smtpOverride['port'] ?? null,
'smtp_secure' => $smtpOverride['secure'] ?? null,
'ok' => $ok,
'error' => $ok ? null : $this->lastMailError,
]);
if (!$ok) {
$this->fail('SMTP test failed', $this->lastMailError ?: 'Send failed', 500);
}
$this->respond(['ok' => true, 'to' => $recipient]);
}
private function handleAccountSettingsUpdate(): void private function handleAccountSettingsUpdate(): void
{ {
$user = $this->requireAuth(); $user = $this->requireAuth();
@@ -3838,13 +3895,14 @@ class ApiKernel
$hasSmtpFromEmail = array_key_exists('smtp_from_email', $this->in); $hasSmtpFromEmail = array_key_exists('smtp_from_email', $this->in);
$hasSmtpFromName = array_key_exists('smtp_from_name', $this->in); $hasSmtpFromName = array_key_exists('smtp_from_name', $this->in);
$hasSmtpReplyTo = array_key_exists('smtp_reply_to', $this->in); $hasSmtpReplyTo = array_key_exists('smtp_reply_to', $this->in);
$hasSmtpPassClear = array_key_exists('smtp_pass_clear', $this->in);
$rotateBridge = !empty($this->in['rotate_bridge_token']); $rotateBridge = !empty($this->in['rotate_bridge_token']);
$rotateSender = !empty($this->in['rotate_sender_token']); $rotateSender = !empty($this->in['rotate_sender_token']);
$rotateExternal = !empty($this->in['rotate_external_token']); $rotateExternal = !empty($this->in['rotate_external_token']);
$onlyListSort = $hasListSort && !$hasBridgeUrl && !$hasBridgeToken && !$hasSenderToken && !$hasExternalToken $onlyListSort = $hasListSort && !$hasBridgeUrl && !$hasBridgeToken && !$hasSenderToken && !$hasExternalToken
&& !$hasEditorDefault && !$hasBridgeTables && !$hasVersionsRetention && !$rotateBridge && !$rotateSender && !$rotateExternal && !$hasEditorDefault && !$hasBridgeTables && !$hasVersionsRetention && !$rotateBridge && !$rotateSender && !$rotateExternal
&& !$hasSmtpEnabled && !$hasSmtpHost && !$hasSmtpPort && !$hasSmtpUser && !$hasSmtpPass && !$hasSmtpSecure && !$hasSmtpEnabled && !$hasSmtpHost && !$hasSmtpPort && !$hasSmtpUser && !$hasSmtpPass && !$hasSmtpSecure
&& !$hasSmtpFromEmail && !$hasSmtpFromName && !$hasSmtpReplyTo; && !$hasSmtpFromEmail && !$hasSmtpFromName && !$hasSmtpReplyTo && !$hasSmtpPassClear;
if (!$onlyListSort) { if (!$onlyListSort) {
$this->ensureRole($user, ['owner', 'admin']); $this->ensureRole($user, ['owner', 'admin']);
@@ -3869,6 +3927,7 @@ class ApiKernel
$smtpFromEmail = $hasSmtpFromEmail ? trim((string)($this->in['smtp_from_email'] ?? '')) : (string)($settings['smtp_from_email'] ?? ''); $smtpFromEmail = $hasSmtpFromEmail ? trim((string)($this->in['smtp_from_email'] ?? '')) : (string)($settings['smtp_from_email'] ?? '');
$smtpFromName = $hasSmtpFromName ? trim((string)($this->in['smtp_from_name'] ?? '')) : (string)($settings['smtp_from_name'] ?? ''); $smtpFromName = $hasSmtpFromName ? trim((string)($this->in['smtp_from_name'] ?? '')) : (string)($settings['smtp_from_name'] ?? '');
$smtpReplyTo = $hasSmtpReplyTo ? trim((string)($this->in['smtp_reply_to'] ?? '')) : (string)($settings['smtp_reply_to'] ?? ''); $smtpReplyTo = $hasSmtpReplyTo ? trim((string)($this->in['smtp_reply_to'] ?? '')) : (string)($settings['smtp_reply_to'] ?? '');
$smtpPassClear = $hasSmtpPassClear ? !empty($this->in['smtp_pass_clear']) : false;
if ($bridgeUrl && !filter_var($bridgeUrl, FILTER_VALIDATE_URL)) { if ($bridgeUrl && !filter_var($bridgeUrl, FILTER_VALIDATE_URL)) {
$this->fail('Ungültige Bridge-URL', null, 422); $this->fail('Ungültige Bridge-URL', null, 422);
@@ -3911,7 +3970,7 @@ class ApiKernel
$smtpSecure = ''; $smtpSecure = '';
} }
$settings = $this->saveCustomerSettings($customerId, [ $save = [
'bridge_url' => $bridgeUrl, 'bridge_url' => $bridgeUrl,
'bridge_token' => $bridgeToken, 'bridge_token' => $bridgeToken,
'sender_token' => $senderToken, 'sender_token' => $senderToken,
@@ -3923,12 +3982,18 @@ class ApiKernel
'smtp_host' => $smtpHost ?: null, 'smtp_host' => $smtpHost ?: null,
'smtp_port' => $smtpPort > 0 ? $smtpPort : null, 'smtp_port' => $smtpPort > 0 ? $smtpPort : null,
'smtp_user' => $smtpUser ?: null, 'smtp_user' => $smtpUser ?: null,
'smtp_pass' => $smtpPass !== '' ? $smtpPass : null,
'smtp_secure' => $smtpSecure ?: null, 'smtp_secure' => $smtpSecure ?: null,
'smtp_from_email' => $smtpFromEmail ?: null, 'smtp_from_email' => $smtpFromEmail ?: null,
'smtp_from_name' => $smtpFromName ?: null, 'smtp_from_name' => $smtpFromName ?: null,
'smtp_reply_to' => $smtpReplyTo ?: null, 'smtp_reply_to' => $smtpReplyTo ?: null,
]); ];
if ($smtpPassClear) {
$save['smtp_pass'] = null;
} elseif ($hasSmtpPass && $smtpPass !== '') {
$save['smtp_pass'] = $smtpPass;
}
$settings = $this->saveCustomerSettings($customerId, $save);
} else { } else {
$settings = $customerId ? $this->ensureSettingsTokens($customerId, $settings) : $settings; $settings = $customerId ? $this->ensureSettingsTokens($customerId, $settings) : $settings;
} }
@@ -4600,6 +4665,8 @@ class ApiKernel
} else { } else {
$row['smtp_port'] = 0; $row['smtp_port'] = 0;
} }
$row['smtp_pass_set'] = !empty($row['smtp_pass']);
unset($row['smtp_pass']);
return $row; return $row;
} }