mirror of
https://github.com/xodivorce/mailer-dev-console.git
synced 2025-12-19 23:59:34 +05:30
(chore): initial MVP release
This commit is contained in:
538
htdocs/app/preview/outbox.php
Normal file
538
htdocs/app/preview/outbox.php
Normal file
@@ -0,0 +1,538 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../mail/mailer.php';
|
||||
require_once __DIR__ . '/../mail/templates/loader.php';
|
||||
|
||||
$selectedTemplate = $_POST['tpl'] ?? $_GET['tpl'] ?? 'quary';
|
||||
|
||||
$validTemplates = array_keys(mailTemplateMap());
|
||||
if (!in_array($selectedTemplate, $validTemplates, true)) {
|
||||
$selectedTemplate = 'quary';
|
||||
}
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$sent = sendAccountCreationMail(false, $selectedTemplate);
|
||||
$code = $sent ? 'ok' : 'fail';
|
||||
header('Location: ' . $_SERVER['PHP_SELF'] . '?status=' . $code . '&tpl=' . urlencode($selectedTemplate));
|
||||
exit;
|
||||
}
|
||||
|
||||
sendAccountCreationMail(true, $selectedTemplate);
|
||||
|
||||
$subject = $GLOBALS['MAIL_PREVIEW_SUBJECT'] ?? '(no subject)';
|
||||
$body = $GLOBALS['MAIL_PREVIEW_BODY'] ?? '';
|
||||
$to = $GLOBALS['MAIL_PREVIEW_TO'] ?? '';
|
||||
$username = $GLOBALS['MAIL_PREVIEW_USERNAME'] ?? '';
|
||||
$domain = $GLOBALS['MAIL_PREVIEW_DOMAIN'] ?? '';
|
||||
$company = $GLOBALS['MAIL_PREVIEW_COMPANY'] ?? '';
|
||||
$github = $GLOBALS['MAIL_PREVIEW_GITHUB'] ?? '';
|
||||
$website = $GLOBALS['MAIL_PREVIEW_WEBSITE'] ?? '';
|
||||
$fromEmail = $GLOBALS['MAIL_PREVIEW_FROM'] ?? '';
|
||||
$fromName = $GLOBALS['MAIL_PREVIEW_FROM_NAME'] ?? '';
|
||||
|
||||
$smtpHost = $GLOBALS['MAIL_PREVIEW_MAIL_HOST'] ?? '';
|
||||
$smtpUser = $GLOBALS['MAIL_PREVIEW_MAIL_USERNAME'] ?? '';
|
||||
$smtpPort = $GLOBALS['MAIL_PREVIEW_MAIL_PORT'] ?? '';
|
||||
$smtpEncryption = $GLOBALS['MAIL_PREVIEW_MAIL_ENCRYPTION'] ?? '';
|
||||
$smtpPassword = $GLOBALS['MAIL_PREVIEW_MAIL_PASSWORD'] ?? '';
|
||||
$projectStart = $GLOBALS['MAIL_PREVIEW_PROJECT_START'] ?? '';
|
||||
$currentYear = $GLOBALS['MAIL_PREVIEW_CURRENT_YEAR'] ?? '';
|
||||
|
||||
$templateIndex = $GLOBALS['MAIL_PREVIEW_TEMPLATES_INDEX'] ?? [];
|
||||
$templateLabel = $GLOBALS['MAIL_PREVIEW_TEMPLATE_LABEL'] ?? '';
|
||||
$templateKey = $GLOBALS['MAIL_PREVIEW_TEMPLATE_KEY'] ?? $selectedTemplate;
|
||||
|
||||
/**
|
||||
* Build a full state snapshot so ANY change (template or mail config)
|
||||
* will change the hash and trigger a live refresh.
|
||||
*/
|
||||
$previewState = [
|
||||
'body' => $body,
|
||||
'subject' => $subject,
|
||||
'to' => $to,
|
||||
'username' => $username,
|
||||
'domain' => $domain,
|
||||
'company' => $company,
|
||||
'fromName' => $fromName,
|
||||
'fromEmail' => $fromEmail,
|
||||
'smtpHost' => $smtpHost,
|
||||
'smtpUser' => $smtpUser,
|
||||
'smtpPort' => $smtpPort,
|
||||
'smtpEncryption' => $smtpEncryption,
|
||||
// we only care if a password exists, not the value itself
|
||||
'hasSmtpPassword' => (bool) $smtpPassword,
|
||||
'projectStart' => $projectStart,
|
||||
'currentYear' => $currentYear,
|
||||
];
|
||||
|
||||
$bodyHash = sha1(json_encode($previewState, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
|
||||
|
||||
if (isset($_GET['mode']) && $_GET['mode'] === 'json') {
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
echo json_encode([
|
||||
'hash' => $bodyHash,
|
||||
'state' => $previewState,
|
||||
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Status banner state
|
||||
*/
|
||||
$statusKind = null; // 'success' | 'error' | null
|
||||
$statusMessage = null;
|
||||
|
||||
if (isset($_GET['status'])) {
|
||||
if ($_GET['status'] === 'ok') {
|
||||
$statusKind = 'success';
|
||||
$statusMessage = "Email sent successfully to {$to}";
|
||||
} elseif ($_GET['status'] === 'fail') {
|
||||
$statusKind = 'error';
|
||||
$statusMessage = "Failed to send email. Check error logs.";
|
||||
}
|
||||
}
|
||||
?>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Mail Renderer - Xovae</title>
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||
|
||||
<link href="https://fonts.googleapis.com/css2?family=Lexend+Deca:wght@300;400;500;600;700&display=swap"
|
||||
rel="stylesheet" />
|
||||
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<script>
|
||||
tailwind.config = {
|
||||
theme: {
|
||||
extend: {
|
||||
fontFamily: {
|
||||
sans: ['"Lexend Deca"', 'system-ui', 'sans-serif'],
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.grid-pattern {
|
||||
background-image:
|
||||
linear-gradient(to right, rgba(148, 163, 184, 0.08) 1px, transparent 1px),
|
||||
linear-gradient(to bottom, rgba(148, 163, 184, 0.08) 1px, transparent 1px);
|
||||
background-size: 24px 24px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body class="bg-slate-50 text-slate-900 min-h-screen font-sans antialiased">
|
||||
<div class="min-h-screen flex flex-col">
|
||||
<header class="bg-slate-900 text-white border-b border-slate-700">
|
||||
<div class="max-w-[1800px] mx-auto px-6 py-6">
|
||||
<div class="flex flex-col gap-6 lg:flex-row lg:items-center lg:justify-between">
|
||||
<div class="flex items-center gap-4">
|
||||
<div
|
||||
class="flex items-center justify-center w-12 h-12 bg-blue-600 text-white font-bold text-lg rounded-md">
|
||||
<?= strtoupper(substr($domain ?: 'UD', 0, 2)) ?>
|
||||
</div>
|
||||
<div>
|
||||
<h1 class="text-2xl font-semibold tracking-tight" id="domainTitle">
|
||||
<?= htmlspecialchars($domain ?: 'MAIL PREVIEW CONSOLE') ?>
|
||||
</h1>
|
||||
<p class="text-xs font-medium text-slate-400 tracking-[0.18em] mt-0.5">
|
||||
Mail Template Review & Delivery Workspace
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col sm:flex-row items-start sm:items-center gap-3">
|
||||
<form method="get"
|
||||
class="flex items-center gap-3 bg-slate-800/90 border border-slate-700 px-4 py-2.5 rounded-lg">
|
||||
<label class="text-xs font-semibold text-slate-400 uppercase tracking-wider">
|
||||
TEMPLATE
|
||||
</label>
|
||||
<div class="relative">
|
||||
<select name="tpl" class="appearance-none bg-slate-700 border border-slate-600 text-white text-sm
|
||||
pl-3 pr-8 py-1.5 rounded-md
|
||||
focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500
|
||||
cursor-pointer" onchange="this.form.submit()">
|
||||
<?php foreach ($templateIndex as $tpl): ?>
|
||||
<option value="<?= htmlspecialchars($tpl['key']) ?>"
|
||||
<?= $tpl['key'] === $templateKey ? 'selected' : '' ?>>
|
||||
<?= htmlspecialchars($tpl['label']) ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
<svg class="pointer-events-none absolute right-2 top-1/2 -translate-y-1/2 w-4 h-4 text-slate-300"
|
||||
fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M19 9l-7 7-7-7" />
|
||||
</svg>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<form method="post" onsubmit="handleSendEmail(event)">
|
||||
<input type="hidden" name="tpl" value="<?= htmlspecialchars($templateKey) ?>" />
|
||||
<button type="submit" name="send" id="sendButton" class="bg-blue-600 hover:bg-blue-700 text-white px-6 py-2.5 rounded font-medium text-sm
|
||||
transition-colors focus:outline-none focus:ring-2
|
||||
focus:ring-blue-500 focus:ring-offset-2 focus:ring-offset-slate-900
|
||||
flex items-center gap-2">
|
||||
<svg id="sendIcon" class="w-4 h-4" fill="none" stroke="currentColor"
|
||||
viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M12 19l9 2-9-18-9 18 9-2zm0 0v-8" />
|
||||
</svg>
|
||||
<svg id="loadingIcon" class="w-4 h-4 animate-spin hidden" fill="none"
|
||||
stroke="currentColor" viewBox="0 0 24 24">
|
||||
<circle class="opacity-25" cx="12" cy="12" r="10" stroke-width="4" />
|
||||
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0
|
||||
3.042 1.135 5.824 3 7.938l3-2.647z" />
|
||||
</svg>
|
||||
<span id="sendText">Send Email</span>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<?php if ($statusKind && $statusMessage): ?>
|
||||
<div class="bg-white border-b border-slate-200">
|
||||
<div class="max-w-[1800px] mx-auto px-6 py-3">
|
||||
<div
|
||||
class="flex items-center gap-3 <?= $statusKind === 'success' ? 'text-green-700' : 'text-red-700' ?>">
|
||||
<div
|
||||
class="flex items-center justify-center w-8 h-8 rounded-full <?= $statusKind === 'success' ? 'bg-green-100' : 'bg-red-100' ?>">
|
||||
<span class="text-lg font-bold">
|
||||
<?= $statusKind === 'success' ? '✓' : '✕' ?>
|
||||
</span>
|
||||
</div>
|
||||
<p class="font-medium text-sm"><?= htmlspecialchars($statusMessage) ?></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="flex-1 max-w-[1800px] mx-auto w-full px-6 py-6">
|
||||
<div class="grid grid-cols-1 xl:grid-cols-[380px,minmax(0,1fr)] gap-6 h-full">
|
||||
<section class="bg-white border border-slate-200 shadow-sm rounded-lg overflow-hidden flex flex-col">
|
||||
<div class="bg-slate-800 text-white px-5 py-4 border-b border-slate-700">
|
||||
<h2 class="font-semibold text-sm tracking-wider">
|
||||
Message Configurations From .env
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<div class="flex-1 overflow-y-auto px-5 py-5 space-y-6 text-sm">
|
||||
<div>
|
||||
<h3
|
||||
class="text-xs font-semibold uppercase tracking-wider text-slate-500 mb-3 pb-2 border-b border-slate-200">
|
||||
Message Details
|
||||
</h3>
|
||||
<dl class="space-y-3">
|
||||
<div>
|
||||
<dt class="text-[11px] font-semibold text-slate-500 uppercase tracking-wider mb-1">
|
||||
From
|
||||
</dt>
|
||||
<dd class="text-slate-900">
|
||||
<div class="font-medium" id="fromNameValue">
|
||||
<?= htmlspecialchars($fromName ?: 'N/A') ?>
|
||||
</div>
|
||||
<div class="text-xs text-slate-500" id="fromEmailValue">
|
||||
<?= htmlspecialchars($fromEmail ?: 'N/A') ?>
|
||||
</div>
|
||||
</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt class="text-[11px] font-semibold text-slate-500 uppercase tracking-wider mb-1">
|
||||
To
|
||||
</dt>
|
||||
<dd class="text-slate-900">
|
||||
<div class="font-medium" id="toNameValue">
|
||||
<?= htmlspecialchars($username ?: 'User') ?>
|
||||
</div>
|
||||
<div class="text-xs text-slate-500" id="toEmailValue">
|
||||
<?= htmlspecialchars($to ?: 'N/A') ?>
|
||||
</div>
|
||||
</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt class="text-[11px] font-semibold text-slate-500 uppercase tracking-wider mb-1">
|
||||
Subject
|
||||
</dt>
|
||||
<dd class="font-medium text-slate-900" id="subjectValue">
|
||||
<?= htmlspecialchars($subject) ?>
|
||||
</dd>
|
||||
</div>
|
||||
</dl>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3
|
||||
class="text-xs font-semibold uppercase tracking-wider text-slate-500 mb-3 pb-2 border-b border-slate-200">
|
||||
Organization
|
||||
</h3>
|
||||
<dl class="space-y-3">
|
||||
<div>
|
||||
<dt class="text-[11px] font-semibold text-slate-500 uppercase tracking-wider mb-1">
|
||||
Domain
|
||||
</dt>
|
||||
<dd class="font-medium text-slate-900" id="domainValue">
|
||||
<?= htmlspecialchars($domain ?: '—') ?>
|
||||
</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt class="text-[11px] font-semibold text-slate-500 uppercase tracking-wider mb-1">
|
||||
Company
|
||||
</dt>
|
||||
<dd class="font-medium text-slate-900" id="companyValue">
|
||||
<?= htmlspecialchars($company ?: '—') ?>
|
||||
</dd>
|
||||
</div>
|
||||
</dl>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3
|
||||
class="text-xs font-semibold uppercase tracking-wider text-slate-500 mb-3 pb-2 border-slate-200 border-b">
|
||||
SMTP Configuration
|
||||
</h3>
|
||||
<dl class="space-y-3">
|
||||
<div>
|
||||
<dt class="text-[11px] font-semibold text-slate-500 uppercase tracking-wider mb-1">
|
||||
Host
|
||||
</dt>
|
||||
<dd class="text-xs text-slate-900" id="smtpHostValue">
|
||||
<?= htmlspecialchars($smtpHost ?: '—') ?>
|
||||
</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt class="text-[11px] font-semibold text-slate-500 uppercase tracking-wider mb-1">
|
||||
Username
|
||||
</dt>
|
||||
<dd class="text-xs text-slate-900" id="smtpUserValue">
|
||||
<?= htmlspecialchars($smtpUser ?: '—') ?>
|
||||
</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt class="text-[11px] font-semibold text-slate-500 uppercase tracking-wider mb-1">
|
||||
Port
|
||||
</dt>
|
||||
<dd class="text-xs text-slate-900" id="smtpPortValue">
|
||||
<?= htmlspecialchars($smtpPort ?: '—') ?>
|
||||
</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt class="text-[11px] font-semibold text-slate-500 uppercase tracking-wider mb-1">
|
||||
Encryption
|
||||
</dt>
|
||||
<dd class="text-xs text-slate-900" id="smtpEncValue">
|
||||
<?= htmlspecialchars($smtpEncryption ?: '—') ?>
|
||||
</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt class="text-[11px] font-semibold text-slate-500 uppercase tracking-wider mb-1">
|
||||
Password
|
||||
</dt>
|
||||
<dd class="text-xs text-slate-500" id="smtpPwdValue">
|
||||
<?= htmlspecialchars($smtpPassword ? '••••••••' : '—') ?>
|
||||
</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt class="text-[11px] font-semibold text-slate-500 uppercase tracking-wider mb-1">
|
||||
Project Timeline
|
||||
</dt>
|
||||
<dd class="text-xs text-slate-900" id="projectTimelineValue">
|
||||
<?php if ($projectStart && $currentYear): ?>
|
||||
<?= htmlspecialchars($projectStart) ?> – <?= htmlspecialchars($currentYear) ?>
|
||||
<?php else: ?>
|
||||
<span class="text-slate-400">—</span>
|
||||
<?php endif; ?>
|
||||
</dd>
|
||||
</div>
|
||||
</dl>
|
||||
</div>
|
||||
|
||||
<div class="bg-slate-50 border border-slate-200 rounded p-4">
|
||||
<h3 class="text-xs font-semibold uppercase tracking-wider text-slate-700 mb-2">
|
||||
Documentation
|
||||
</h3>
|
||||
<p class="text-xs leading-relaxed text-slate-600">
|
||||
Preview live-rendered HTML email templates are generated by PHPMailer.
|
||||
To modify a template, edit
|
||||
<code class="text-[10px] bg-white px-1.5 py-0.5 border border-slate-300 rounded">
|
||||
app/mail/mailer.php
|
||||
</code>
|
||||
and manage template definitions in
|
||||
<code class="text-[10px] bg-white px-1.5 py-0.5 border border-slate-300 rounded">
|
||||
app/mail/templates/loader.php
|
||||
</code>.
|
||||
For more, visit
|
||||
<a href="https://github.com/xodivorce/mailer-dev-console" target="_blank"
|
||||
class="text-[#0f172a] hover:text-[#0f172acb] underline">
|
||||
xodivorce/mailer-dev-console
|
||||
</a>.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section
|
||||
class="bg-white border border-slate-200 shadow-sm rounded-lg overflow-hidden flex flex-col min-h-[700px]">
|
||||
<div class="bg-slate-100 border-b border-slate-200 px-5 py-4">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center gap-3">
|
||||
<div id="livePreviewBadge"
|
||||
class="flex items-center justify-center w-10 h-8 bg-slate-700 text-white text-xs rounded transition-colors duration-200">
|
||||
HTML
|
||||
</div>
|
||||
<div>
|
||||
<h2 class="font-semibold text-slate-900 text-base">
|
||||
Rendering Console
|
||||
</h2>
|
||||
<p id="previewSubjectLine" class="text-xs text-slate-500 mt-0.5 leading-snug">
|
||||
<?= htmlspecialchars($subject) ?>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-xs font-semibold text-slate-600 tracking-wider">
|
||||
iFRAME RENDERING..
|
||||
</span>
|
||||
<span class="relative flex h-2 w-2">
|
||||
<span
|
||||
class="animate-ping absolute inline-flex h-full w-full rounded-full bg-green-400 opacity-75"></span>
|
||||
<span class="relative inline-flex rounded-full h-2 w-2 bg-green-500"></span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex-1 grid-pattern bg-slate-50 p-2">
|
||||
<iframe id="previewFrame"
|
||||
class="w-full h-full bg-white border border-slate-200 rounded shadow-inner"
|
||||
srcdoc="<?= htmlspecialchars($body, ENT_QUOTES, 'UTF-8') ?>"></iframe>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const MAILER_INITIAL_HASH = "<?= htmlspecialchars($bodyHash, ENT_QUOTES, 'UTF-8') ?>";
|
||||
const MAILER_TPL_KEY = "<?= htmlspecialchars($templateKey, ENT_QUOTES, 'UTF-8') ?>";
|
||||
const MAILER_PHP_SELF = "<?= htmlspecialchars($_SERVER['PHP_SELF'], ENT_QUOTES, 'UTF-8') ?>";
|
||||
|
||||
let currentHash = MAILER_INITIAL_HASH;
|
||||
|
||||
function handleSendEmail(event) {
|
||||
const button = document.getElementById('sendButton');
|
||||
const sendIcon = document.getElementById('sendIcon');
|
||||
const loadingIcon = document.getElementById('loadingIcon');
|
||||
const sendText = document.getElementById('sendText');
|
||||
|
||||
button.disabled = true;
|
||||
button.classList.add('opacity-75', 'cursor-not-allowed');
|
||||
button.classList.remove('hover:bg-blue-700');
|
||||
|
||||
sendIcon.classList.add('hidden');
|
||||
loadingIcon.classList.remove('hidden');
|
||||
sendText.textContent = 'Processing...';
|
||||
}
|
||||
|
||||
function flashLivePreviewBadge() {
|
||||
const badge = document.getElementById('livePreviewBadge');
|
||||
if (!badge) return;
|
||||
badge.classList.remove('bg-slate-700');
|
||||
badge.classList.add('bg-green-600');
|
||||
setTimeout(() => {
|
||||
badge.classList.remove('bg-green-600');
|
||||
badge.classList.add('bg-slate-700');
|
||||
}, 600);
|
||||
}
|
||||
|
||||
function setText(id, value) {
|
||||
const el = document.getElementById(id);
|
||||
if (el) {
|
||||
el.textContent = value;
|
||||
}
|
||||
}
|
||||
|
||||
async function pollTemplateChanges() {
|
||||
try {
|
||||
const params = new URLSearchParams({
|
||||
tpl: MAILER_TPL_KEY,
|
||||
mode: 'json',
|
||||
_: Date.now().toString(),
|
||||
});
|
||||
|
||||
const res = await fetch(MAILER_PHP_SELF + '?' + params.toString(), {
|
||||
cache: 'no-store',
|
||||
});
|
||||
|
||||
if (!res.ok) throw new Error('Preview poll failed');
|
||||
|
||||
const data = await res.json();
|
||||
if (!data || !data.hash || !data.state) return;
|
||||
|
||||
if (data.hash !== currentHash) {
|
||||
currentHash = data.hash;
|
||||
|
||||
const s = data.state;
|
||||
|
||||
// iframe + subject
|
||||
const iframe = document.getElementById('previewFrame');
|
||||
const subjectLine = document.getElementById('previewSubjectLine');
|
||||
|
||||
if (iframe && typeof s.body === 'string') {
|
||||
iframe.srcdoc = s.body;
|
||||
}
|
||||
if (subjectLine && typeof s.subject === 'string') {
|
||||
subjectLine.textContent = s.subject || '(no subject)';
|
||||
}
|
||||
setText('subjectValue', s.subject || '(no subject)');
|
||||
|
||||
// message details
|
||||
setText('fromNameValue', s.fromName || 'N/A');
|
||||
setText('fromEmailValue', s.fromEmail || 'N/A');
|
||||
setText('toNameValue', s.username || 'User');
|
||||
setText('toEmailValue', s.to || 'N/A');
|
||||
|
||||
// org
|
||||
setText('domainValue', s.domain || '—');
|
||||
setText('companyValue', s.company || '—');
|
||||
|
||||
// header title domain
|
||||
const domainTitle = document.getElementById('domainTitle');
|
||||
if (domainTitle) {
|
||||
domainTitle.textContent = s.domain || 'MAIL PREVIEW CONSOLE';
|
||||
}
|
||||
|
||||
// smtp
|
||||
setText('smtpHostValue', s.smtpHost || '—');
|
||||
setText('smtpUserValue', s.smtpUser || '—');
|
||||
setText('smtpPortValue', s.smtpPort || '—');
|
||||
setText('smtpEncValue', s.smtpEncryption || '—');
|
||||
setText('smtpPwdValue', s.hasSmtpPassword ? '••••••••' : '—');
|
||||
|
||||
// project timeline
|
||||
const timeline = (s.projectStart && s.currentYear)
|
||||
? (s.projectStart + ' – ' + s.currentYear)
|
||||
: '—';
|
||||
setText('projectTimelineValue', timeline);
|
||||
|
||||
flashLivePreviewBadge();
|
||||
}
|
||||
} catch (err) {
|
||||
// silent fail, retry
|
||||
} finally {
|
||||
setTimeout(pollTemplateChanges, 2000);
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener('DOMContentLoaded', () => {
|
||||
pollTemplateChanges();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
Reference in New Issue
Block a user