Notice: Due to size constraints and loading performance considerations, scripts referenced in blog posts are not attached directly. To request access, please complete the following form: Script Request Form Note: A Google account is required to access the form.
Disclaimer: I do not accept responsibility for any issues arising from scripts being run without adequate understanding. It is the user's responsibility to review and assess any code before execution. More information

HTML : Modernizing SMTP Monitoring Dashboard

This is all about modernising the original SMTP dashboard post which you can find here

I was concerned that the old dashboard was quite dated and the information layout was not easy to read, it also missed "dark mode" which seems to be the normal for monitoring sites at the moment, so lets give this a lick of paint and some optimization.

New UI - same data

This is a visual of the new website which effectively pulls all the information together in simple of understand sections, first is the header section:


Then we finally move on to performance analytics, where you can clearly see the status of the servers that are being monitored in easy to view charts and bars:


Information Overload in Plain Text

I need to work with SMTP monitoring and the logs that look like this as an example:

====================================================
SMTP Server Check - Started at 2025-01-31 14:30:15
====================================================
Domain for MX checks: bythepowerofgreyskull.com
Checking MX server: mailsrv1.bythepowerofgreyskull.com on port 25...
[SUCCESS] TCP connection to mailsrv1.bythepowerofgreyskull.com on port 25 (Response time: 8ms)
Testing SMTP connectivity on port 25 SMTP server appears to be responding [SUCCESS] SMTP service appears to be responding on port 25 Port 25: Standard SMTP port for server-to-server communication

Modern Dashboard

I wanted to create a monitoring solution that would transform raw SMTP logs into a comprehensive dashboard featuring:

  • Real-time system health indicators with color-coded status dots
  • Interactive performance charts showing 24-hour trends
  • Server-specific uptime statistics with visual progress bars
  • Response time analytics including averages, minimums, and maximums
  • Historical timeline of significant system events

Step 1: Intelligent Log Parsing

The first challenge was extracting meaningful data from unstructured log files. I developed a multi-pattern parsing approach that handles both current and legacy log formats:

# Parse server checks and status
$checkMatches = [regex]::Matches($sessionContent, 
    "Checking MX server: (.+?) on port (\d+)\.\.\.[\s\S]*?(\[SUCCESS\]|\[FAILED\]|\[WARNING\])")

# Extract response times from TCP connection lines
$responseTimeMatches = [regex]::Matches($sessionContent, 
    "\[SUCCESS\] TCP connection to (.+?) on port (\d+) \(Response time: (\d+)ms\)")

# Create lookup table for response times
$responseTimeLookup = @{}
foreach ($rtMatch in $responseTimeMatches) {
    $key = "$($rtMatch.Groups[1].Value.Trim()):$($rtMatch.Groups[2].Value)"
    $responseTimeLookup[$key] = [int]$rtMatch.Groups[3].Value
}

This approach separates concerns—first capturing the basic connectivity tests, then correlating them with performance metrics. The script intelligently handles cases where response times might not be available while ensuring data integrity.

Step 2: Time-Aware Analytics Engine

Raw logs are just snapshots in time. To create meaningful insights, I built an analytics engine that processes historical data into actionable metrics:

# Calculate analytics for the last 24 hours
$now = Get-Date
$last24Hours = $now.AddHours(-24)
$recent24hSessions = $allSessions | Where-Object { $_.Timestamp -ge $last24Hours }

# Generate hourly performance buckets
$chartData = @()
for ($i = 23; $i -ge 0; $i--) {
    $hourStart = $now.AddHours(-$i - 1)
    $hourEnd = $now.AddHours(-$i)
    
    $hourSessions = $recent24hSessions | Where-Object { 
        $_.Timestamp -ge $hourStart -and $_.Timestamp -lt $hourEnd 
    }
    
    # Calculate hourly uptime and response time averages
    $hourUptime = if ($hourChecks -gt 0) { ($hourSuccess / $hourChecks) * 100 } else { 100 }
    $hourAvgResponse = if ($hourResponseTimes.Count -gt 0) { 
        ($hourResponseTimes | Measure-Object -Average).Average 
    } else { $avgResponseTime }
}

This creates a rolling 24-hour view with hourly granularity, allowing the dashboard to show both current status and performance trends over time.

Step 3: Server-Specific Performance Tracking

Rather than treating all servers as a monolithic system, the script tracks individual server performance:

# Per-server statistics calculation
foreach ($session in $recent24hSessions) {
    foreach ($check in $session.PortChecks) {
        if (-not $serverStats.ContainsKey($check.Server)) {
            $serverStats[$check.Server] = @{
                Total = 0
                Success = 0
                ResponseTimes = @()
            }
        }
        
        $serverStats[$check.Server].Total++
        if ($check.Status -eq "SUCCESS") {
            $serverStats[$check.Server].Success++
        }
        if ($check.ResponseTime) {
            $serverStats[$check.Server].ResponseTimes += $check.ResponseTime
        }
    }
}

This granular approach enables the dashboard to highlight which specific servers might be experiencing issues, rather than just showing overall system health.

Visual Design - with CSS3

I chose a dark theme with subtle gradients effects to create a modern, professional appearance:

body {
    font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
    background: #0a0a0a;
    color: #ffffff;
}

/* Subtle gradient background */
body::before {
    content: '';
    position: fixed;
    background: 
        radial-gradient(circle at 20% 20%, rgba(120, 119, 198, 0.08) 0%, transparent 50%),
        radial-gradient(circle at 80% 80%, rgba(255, 119, 198, 0.06) 0%, transparent 50%);
}

.status-card {
    background: rgba(255, 255, 255, 0.02);
    border: 1px solid rgba(255, 255, 255, 0.06);
    border-radius: 12px;
    backdrop-filter: blur(10px);
    transition: all 0.2s ease;
}

Interactive Data Visualization

The dashboard features SVG-based charts that provide immediate visual feedback about system performance:

<svg class="chart-svg" viewBox="0 0 400 200">
    <!-- Success rate area with gradient fill -->
    <path d="$successArea" class="chart-area"/>
    
    <!-- Success rate line (green) -->
    <path d="$successPath" class="chart-line success-line"/>
    
    <!-- Response time line (blue) -->
    <path d="$responsePath" class="chart-line response-line"/>
    
    <!-- Interactive data points -->
    <circle cx="$($chartData[0].X)" cy="$($chartData[0].UptimeY)" class="chart-dot"/>
</svg>

The charts dynamically scale based on actual data ranges, ensuring that small performance variations are visible while maintaining context for larger issues.

Status Indicators with Smart Contextual Information

Each server connection is represented by an intelligent status indicator that shows not just success/failure, but contextual performance data:

$statusIndicatorsHtml += @"
<div class="status-item">
    <div class="status-indicator $dotClass"></div>
    <div class="status-text">$($check.Server)</div>
    <div class="status-meta">$($check.Port)$responseText</div>
</div>
"@

This approach provides immediate visual scanning capability—green dots indicate healthy servers, while response times give performance context at a glance.

DateTime Sorting Challenge

One particularly tricky bug involved session timestamps not displaying correctly on the dashboard. The script would parse multiple sessions correctly, but the "latest" session shown was actually from hours earlier, not the most recent log entry.

The issue stemmed from PowerShell's Sort-Object behavior with DateTime objects:

# This approach sometimes failed due to property resolution issues
$allSessions = $allSessions | Sort-Object -Property Timestamp -Descending

# However if I use a script block to force proper DateTime comparison this then works
$allSessions = $allSessions | Sort-Object { $_.Timestamp } -Descending

When using -Property Timestamp, PowerShell occasionally treated the DateTime objects as strings, resulting in lexicographic sorting instead of chronological sorting. This meant that "2025-07-31 07:17:40" would appear "newer" than "2025-07-31 10:00:15" because "07" comes before "10" alphabetically.

Response Time Parsing

Another challenge involved accurately extracting response times from log entries. The initial regex pattern looked for response times at the end of status blocks, but the actual log format placed them within TCP connection success messages:

[SUCCESS] TCP connection to mailsrv1.bythepowerofgreyskull.com on port 25 (Response time: 8ms)

I solved this by separating concerns—first parsing connection status, then correlating with response time data:

# Parse connection status separately from response times
$checkMatches = [regex]::Matches($sessionContent, "Checking MX server: (.+?) on port (\d+)")
$responseTimeMatches = [regex]::Matches($sessionContent, "\[SUCCESS\] TCP connection to (.+?) on port (\d+) \(Response time: (\d+)ms\)")

# Create lookup table for correlation
$responseTimeLookup = @{}
foreach ($rtMatch in $responseTimeMatches) {
    $key = "$($rtMatch.Groups[1].Value.Trim()):$($rtMatch.Groups[2].Value)"
    $responseTimeLookup[$key] = [int]$rtMatch.Groups[3].Value
}

This approach proved much more reliable than trying to capture everything in a single complex regex pattern.

Conclusion

When you build an SMTP monitoring dashboard it teaches you that effective monitoring isn't just about collecting data—it's about presenting information in a way that enables quick decision-making and proactive system management.

The transformation from raw log files to an interactive dashboard represents more than just a technical upgrade; it's a fundamental shift from reactive to proactive system administration. When monitoring data is presented clearly and beautifully, it becomes a tool that actually gets used, leading to better system reliability and performance.

Previous Post Next Post

نموذج الاتصال