Fluent Builder Pattern
Zetian uses fluent builder pattern for readable and chainable configuration. You can configure all settings in a single expression.
Basic Configuration
Configure your server with SmtpServerBuilder:
using Zetian.Server;
var server = new SmtpServerBuilder()
// Basic Settings
.Port(587) // Port number
.ServerName("My SMTP Server") // Server name
.MaxMessageSizeMB(25) // Max message size (MB)
.MaxRecipients(100) // Max number of recipients
.MaxConnections(50) // Max number of connections
.MaxConnectionsPerIP(10) // Max connections per IP
// Security
.RequireAuthentication() // Authentication required
.RequireSecureConnection() // TLS/SSL required
.Certificate("cert.pfx", "password") // SSL certificate
// SMTP Features
.EnableSmtpUtf8() // UTF-8 support
.EnablePipelining() // Pipeline support
// Timeout Settings
.ConnectionTimeout(TimeSpan.FromMinutes(5))
.CommandTimeout(TimeSpan.FromSeconds(30))
.Build();Basic Settings
- •
Port- SMTP port number - •
ServerName- Server name - •
MaxMessageSizeMB- Max message size - •
MaxRecipients- Max number of recipients
Connection Limits
- •
MaxConnections- Total connection limit - •
MaxConnectionsPerIP- Limit per IP - •
ConnectionTimeout- Connection timeout - •
CommandTimeout- Command timeout
Authentication Configuration
Configure different authentication methods:
using Zetian.Models;
using Zetian.Server;
// Simple authentication
.SimpleAuthentication("admin", "password123")
// Custom authentication
.AuthenticationHandler(async (username, password) =>
{
// Database check
var user = await GetUserAsync(username);
if (user != null && VerifyPassword(password, user.PasswordHash))
{
return AuthenticationResult.Succeed(username);
}
return AuthenticationResult.Fail("Invalid credentials");
})
// Multiple authentication mechanisms
.AddAuthenticationMechanism("PLAIN")
.AddAuthenticationMechanism("LOGIN")PLAIN Auth
Simple username/password
LOGIN Auth
Legacy auth
Custom Auth
Custom handler
Filtering Configuration
Two different filtering approaches:
using Zetian.Server;
using Zetian.Extensions;
// Protocol-Level Filtering (at SMTP command level)
var server = new SmtpServerBuilder()
.Port(25)
// Domain filtering
.WithSenderDomainWhitelist("trusted.com", "partner.org")
.WithSenderDomainBlacklist("spam.com", "junk.org")
.WithRecipientDomainWhitelist("mydomain.com")
// Message size limit
.MaxMessageSizeMB(10)
// Message storage
.WithFileMessageStore(@"C:\smtp_messages", createDateFolders: true)
.Build();
// Event-Based Filtering (after message is received)
server.AddSpamFilter(new[] { "spam.com", "junk.org" });
server.AddSizeFilter(10 * 1024 * 1024); // 10MB
server.AddAllowedDomains("example.com");Protocol-Level Filtering
Early rejection during SMTP commands. More efficient, saves bandwidth.
- • At MAIL FROM/RCPT TO level
- • Bandwidth savings
- • Fast rejection
Event-Based Filtering
Filtering after message is received. More flexible, can check content.
- • Full message content check
- • Complex logic support
- • Dynamic filters
Rate Limiting
Speed limiting for spam protection:
using Zetian.Server;
using Zetian.Models;
using Zetian.Extensions;
// Rate limiting configuration
var rateLimitConfig = new RateLimitConfiguration
{
MaxRequests = 100, // Maximum number of requests
UseSlidingWindow = false, // Fixed or sliding window
Window = TimeSpan.FromHours(1) // Time window
};
server.AddRateLimiting(rateLimitConfig);
// Alternative: Ready-made configurations
server.AddRateLimiting(RateLimitConfiguration.PerDay(1000)); // 1000 per day
server.AddRateLimiting(RateLimitConfiguration.PerHour(100)); // 100 per hour
server.AddRateLimiting(RateLimitConfiguration.PerMinute(10)); // 10 per minuteImportant Note
Rate limiting works based on IP. Be careful in localhost tests. You can keep limits high in development environment.
Health Check Configuration
Monitor your SMTP server's health with built-in HTTP endpoints:
using Zetian.Server;
using Zetian.HealthCheck.Models;
using Zetian.HealthCheck.Options;
using Zetian.HealthCheck.Extensions;
// Simple health check setup
var server = new SmtpServerBuilder()
.Port(25)
.Build();
// Enable health check on port 8080 (localhost)
var healthCheck = server.EnableHealthCheck(8080);
// Or bind to all interfaces
var healthCheck = server.EnableHealthCheck("0.0.0.0", 8080);
// Or with custom service options
var serviceOptions = new HealthCheckServiceOptions
{
// Define HTTP prefixes to listen on
Prefixes = new() { "http://+:8080/health/" }, // Listen on all interfaces
DegradedStatusCode = 200 // HTTP status code for degraded state
};
// SMTP health check options
var smtpOptions = new SmtpHealthCheckOptions
{
CheckMemoryUsage = true, // Include memory metrics
DegradedThresholdPercent = 60, // 60% utilization = degraded
UnhealthyThresholdPercent = 85 // 85% utilization = unhealthy
};
var healthCheck = server.EnableHealthCheck(serviceOptions, smtpOptions);
// Start server with health check and custom checks
await server.StartWithHealthCheckAsync(8080, healthService =>
{
// Add custom health checks
healthService.AddHealthCheck("database", async (ct) =>
{
try
{
// Check database connection
await CheckDatabaseAsync();
return HealthCheckResult.Healthy("Database connected");
}
catch (Exception ex)
{
return HealthCheckResult.Unhealthy("Database unavailable", ex);
}
});
});/health
Overall health status with details about all checks
/livez
Liveness probe for Kubernetes - is the service alive?
/readyz
Readiness probe - is the service ready for traffic?