Zetian.HealthCheck 1.0.8

Prefix Reserved
dotnet add package Zetian.HealthCheck --version 1.0.8
                    
NuGet\Install-Package Zetian.HealthCheck -Version 1.0.8
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Zetian.HealthCheck" Version="1.0.8" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Zetian.HealthCheck" Version="1.0.8" />
                    
Directory.Packages.props
<PackageReference Include="Zetian.HealthCheck" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Zetian.HealthCheck --version 1.0.8
                    
#r "nuget: Zetian.HealthCheck, 1.0.8"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Zetian.HealthCheck@1.0.8
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Zetian.HealthCheck&version=1.0.8
                    
Install as a Cake Addin
#tool nuget:?package=Zetian.HealthCheck&version=1.0.8
                    
Install as a Cake Tool

Zetian.HealthCheck - Health Monitoring for SMTP

NuGet-Version NuGet-Download License

A lightweight health monitoring extension for Zetian SMTP Server, providing HTTP endpoints for health checks, liveness probes, readiness checks, and custom health metrics. Perfect for Kubernetes, Docker Swarm, load balancers, and monitoring systems.

⚑ Features

  • πŸ”„ Real-time Status - Live server health monitoring
  • πŸ“ˆ JSON Response - Structured health data for monitoring tools
  • ☸️ Kubernetes Ready - Built for K8s liveness and readiness probes
  • πŸ” Multiple Endpoints - /health, /health/livez, /health/readyz
  • 🌐 Flexible Binding - Support for localhost, specific IPs, hostnames, IPv6
  • πŸš€ Zero Dependencies - Lightweight, uses only .NET built-in HttpListener
  • 🎯 Custom Checks - Add your own health checks (database, disk, services)
  • πŸ“Š Detailed Metrics - Server uptime, active sessions, memory usage, utilization

πŸ“¦ Installation

# Install Zetian SMTP Server (required)
dotnet add package Zetian

# Install Health Check Extension
dotnet add package Zetian.HealthCheck

πŸš€ Quick Start

Basic Health Check

using Zetian.Server;
using Zetian.HealthCheck.Extensions;

// Create and start SMTP server
var server = SmtpServerBuilder.CreateBasic();
await server.StartAsync();

// Enable health check on port 8080
var healthCheck = server.EnableHealthCheck(8080);
await healthCheck.StartAsync();

// Health check now available at:
// http://localhost:8080/health
// http://localhost:8080/health/livez
// http://localhost:8080/health/readyz

Start Server with Health Check

// Start both SMTP and health check together
var healthCheck = await server.StartWithHealthCheckAsync(8080);

// Or with custom health checks configured inline
await server.StartWithHealthCheckAsync(8080, healthService =>
{
    // Add custom health checks
    healthService.AddHealthCheck("database", async (ct) =>
    {
        try
        {
            await CheckDatabaseAsync();
            return HealthCheckResult.Healthy("Database connected");
        }
        catch (Exception ex)
        {
            return HealthCheckResult.Unhealthy("Database unavailable", ex);
        }
    });
    
    healthService.AddHealthCheck("redis", async (ct) =>
    {
        try
        {
            await CheckRedisAsync();
            return HealthCheckResult.Healthy("Redis connected");
        }
        catch (Exception ex)
        {
            // Redis is not critical, mark as degraded
            return HealthCheckResult.Degraded("Redis unavailable", ex);
        }
    });
});

πŸ› οΈ Advanced Configuration

Custom Port and Path

// Custom port
var healthCheck = server.EnableHealthCheck(9090);

// Custom path (must end with /)
var healthCheck = server.EnableHealthCheck(8080, "/status/");

IP/Hostname Binding

// Bind to all interfaces (accessible externally)
var healthCheck = server.EnableHealthCheck("0.0.0.0", 8080);

// Bind to hostname
var healthCheck = server.EnableHealthCheck("myserver.local", 8080);

// IPv6 support
var healthCheck = server.EnableHealthCheck(IPAddress.IPv6Loopback, 8080);

// Bind to specific IP
var healthCheck = server.EnableHealthCheck(IPAddress.Parse("192.168.1.100"), 8080);

Custom Health Checks

using Zetian.Server;
using Zetian.HealthCheck.Models;
using Zetian.HealthCheck.Extensions;

var healthCheck = server.EnableHealthCheck(8080);

// Add database check
healthCheck.AddHealthCheck("database", async (ct) =>
{
    try
    {
        var isConnected = await CheckDatabaseAsync();
        return isConnected 
            ? HealthCheckResult.Healthy("Database connected")
            : HealthCheckResult.Unhealthy("Database connection failed");
    }
    catch (Exception ex)
    {
        return HealthCheckResult.Unhealthy("Database error", ex);
    }
});

// Add disk space check
healthCheck.AddHealthCheck("disk_space", async (ct) =>
{
    var drive = new DriveInfo("C:\\");
    var freePercent = (double)drive.AvailableFreeSpace / drive.TotalSize * 100;
    
    var data = new Dictionary<string, object>
    {
        ["freePercent"] = Math.Round(freePercent, 2),
        ["totalSpaceGB"] = drive.TotalSize / (1024 * 1024 * 1024),
        ["freeSpaceGB"] = drive.AvailableFreeSpace / (1024 * 1024 * 1024)
    };
    
    if (freePercent < 10)
        return HealthCheckResult.Unhealthy($"Critical: {freePercent:F2}% free", data: data);
    if (freePercent < 20)
        return HealthCheckResult.Degraded($"Low space: {freePercent:F2}% free", data: data);
    
    return HealthCheckResult.Healthy($"Disk space OK: {freePercent:F2}% free", data: data);
});

await healthCheck.StartAsync();

Advanced Options

using Zetian.Server;
using Zetian.HealthCheck.Options;
using Zetian.HealthCheck.Extensions;

// Custom thresholds for SMTP health
var smtpOptions = new SmtpHealthCheckOptions
{
    CheckMemoryUsage = true,       // Include memory metrics
    DegradedThresholdPercent = 60, // Degraded at 60% utilization
    UnhealthyThresholdPercent = 85 // Unhealthy at 85% utilization
};

// Custom service options
var serviceOptions = new HealthCheckServiceOptions
{
    Prefixes = new() { "http://+:8080/health/" },  // Listen on all interfaces
    DegradedStatusCode = 218  // Custom HTTP status for degraded (default: 200)
};

var healthCheck = server.EnableHealthCheck(serviceOptions, smtpOptions);
await healthCheck.StartAsync();

πŸ“Š Response Format

Healthy Response (HTTP 200)

{
  "status": "Healthy",
  "timestamp": "2024-10-22T16:30:00Z",
  "checks": {
    "smtp_server": {
      "status": "Healthy",
      "description": "SMTP server is healthy",
      "data": {
        "status": "running",
        "uptime": "2d 3h 15m 42s",
        "activeSessions": 5,
        "maxSessions": 50,
        "utilizationPercent": 10.0,
        "memoryUsageMB": 45.2
      }
    },
    "database": {
      "status": "Healthy",
      "description": "Database connected"
    },
    "disk_space": {
      "status": "Healthy",
      "description": "Disk space OK: 65.3% free",
      "data": {
        "freeSpaceGB": 250,
        "totalSpaceGB": 500,
        "freePercent": 50.0
      }
    }
  }
}

Degraded Response (HTTP 200 or custom)

{
  "status": "Degraded",
  "timestamp": "2024-10-22T16:30:00Z",
  "checks": {
    "smtp_server": {
      "status": "Degraded",
      "description": "SMTP server utilization is high",
      "data": {
        "activeSessions": 35,
        "maxSessions": 50,
        "utilizationPercent": 70.0
      }
    }
  }
}

Unhealthy Response (HTTP 503)

{
  "status": "Unhealthy",
  "timestamp": "2024-10-22T16:30:00Z",
  "checks": {
    "smtp_server": {
      "status": "Unhealthy",
      "description": "SMTP server is not running"
    }
  }
}

☸️ Kubernetes Integration

Deployment Configuration

apiVersion: apps/v1
kind: Deployment
metadata:
  name: smtp-server
spec:
  replicas: 3
  selector:
    matchLabels:
      app: smtp-server
  template:
    metadata:
      labels:
        app: smtp-server
    spec:
      containers:
      - name: smtp-server
        image: myregistry/smtp-server:latest
        ports:
        - containerPort: 25   # SMTP port
        - containerPort: 8080 # Health check port
        livenessProbe:
          httpGet:
            path: /health/livez
            port: 8080
          initialDelaySeconds: 30
          periodSeconds: 10
          timeoutSeconds: 5
          failureThreshold: 3
        readinessProbe:
          httpGet:
            path: /health/readyz
            port: 8080
          initialDelaySeconds: 10
          periodSeconds: 5
          timeoutSeconds: 3
          failureThreshold: 2

Service Configuration

apiVersion: v1
kind: Service
metadata:
  name: smtp-service
spec:
  selector:
    app: smtp-server
  ports:
  - name: smtp
    port: 25
    targetPort: 25
  - name: health
    port: 8080
    targetPort: 8080

🐳 Docker Integration

Dockerfile Example

FROM mcr.microsoft.com/dotnet/runtime:8.0
WORKDIR /app
COPY . .
EXPOSE 25 8080
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD curl -f http://localhost:8080/health || exit 1
ENTRYPOINT ["dotnet", "MySmtpServer.dll"]

Docker Compose

services:
  smtp:
    image: mysmtp:latest
    ports:
      - "25:25"
      - "8080:8080"
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
      interval: 30s
      timeout: 3s
      retries: 3
      start_period: 40s

🎯 Monitoring Integration

Prometheus Metrics

using Zetian.Server;
using Zetian.HealthCheck.Models;
using Zetian.HealthCheck.Extensions;

// Add custom metrics check for Prometheus
healthCheck.AddHealthCheck("metrics", async (ct) =>
{
    var data = new Dictionary<string, object>
    {
        ["smtp_server_running"] = server.IsRunning,
        ["smtp_server_port"] = server.Configuration.Port,
        ["smtp_max_connections"] = server.Configuration.MaxConnections,
        ["smtp_max_message_size"] = server.Configuration.MaxMessageSize
    };
    
    // Calculate uptime if server is running
    if (server.IsRunning && server.StartTime.HasValue)
    {
        var uptime = DateTime.UtcNow - server.StartTime.Value;
        data["smtp_uptime_seconds"] = uptime.TotalSeconds;
        data["smtp_uptime_formatted"] = $"{uptime.Days}d {uptime.Hours}h {uptime.Minutes}m";
    }
    
    // Add configuration metrics
    if (server.Configuration.RequireAuthentication)
    {
        data["smtp_auth_required"] = true;
    }
    
    return HealthCheckResult.Healthy("Metrics collected", data: data);
});

Grafana/Datadog

Use the JSON endpoints to collect metrics:

# Collect health data
curl http://localhost:8080/health | jq '.checks.smtp_server.data'

# Check liveness
curl -f http://localhost:8080/health/livez

# Check readiness  
curl -f http://localhost:8080/health/readyz

πŸ“ API Reference

Extension Methods

Method Description
EnableHealthCheck(port) Enable health check on localhost
AddHealthCheck(name, checkFunc) Add custom health check to service
StartWithHealthCheckAsync(port) Start server and health check
EnableHealthCheck(hostname, port) Enable on specific hostname
EnableHealthCheck(IPAddress, port) Enable on specific IP
EnableHealthCheck(options, healthOptions) Advanced configuration
StartWithHealthCheckAsync(hostname, port) Start on specific hostname
StartWithHealthCheckAsync(IPAddress, port) Start on specific IP
StartWithHealthCheckAsync(port, configureHealthChecks) Start server with custom health checks
StartWithHealthCheckAsync(hostname, port, configureHealthChecks) Start on hostname with custom checks
StartWithHealthCheckAsync(IPAddress, port, configureHealthChecks) Start on IP with custom checks

Health Check Results

Status HTTP Code Description
Healthy 200 Everything is working
Degraded 200/218 Working but with issues
Unhealthy 503 Critical problems detected

πŸ”§ Troubleshooting

Common Issues

Port Already in Use

// Check if port is available before starting
var listener = new HttpListener();
try
{
    listener.Prefixes.Add("http://localhost:8080/");
    listener.Start();
    listener.Stop();
    // Port is available
}
catch (HttpListenerException)
{
    // Port is in use
}

Access Denied on Non-Localhost

# Windows: Run as administrator or add URL ACL
netsh http add urlacl url=http://+:8080/health/ user=Everyone

# Linux: Use authbind or run as root
sudo setcap cap_net_bind_service=+ep /usr/bin/dotnet

IPv6 Issues

// Check IPv6 support
if (Socket.OSSupportsIPv6)
{
    var healthCheck = server.EnableHealthCheck(IPAddress.IPv6Any, 8080);
}
else
{
    var healthCheck = server.EnableHealthCheck("0.0.0.0", 8080);
}

πŸ“‹ Requirements

  • Windows, Linux, or macOS
  • .NET 6.0, 7.0, 8.0, 9.0, or 10.0
  • Zetian SMTP Server package
  • Administrator privileges for non-localhost binding (Windows)

πŸ“š Documentation & Support

πŸ™ Acknowledgments

  • Built on top of Zetian SMTP Server
  • Community feedback and contributions
  • Inspired by ASP.NET Core Health Checks

πŸ”’ Security

Best Practices:

  • Configure rate limiting
  • Keep the library updated
  • Implement proper authentication
  • Always use TLS/SSL in production

Report Security Issues: taiizor@vegalya.com

πŸ“„ License

MIT License - see LICENSE


Built with ❀️ for the .NET community

Product Compatible and additional computed target framework versions.
.NET net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 is compatible.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.8 680 12/1/2025
1.0.7 121 11/1/2025
1.0.6 233 10/29/2025
1.0.5 148 10/25/2025
1.0.4 6,409 10/23/2025
1.0.3 1,814 10/23/2025
1.0.2 6,678 10/22/2025
1.0.1 1,756 10/22/2025
1.0.0 4,864 10/22/2025

All changes are detailed at https://zetian.soferity.com/changelog.