Smart Host Support
Route through multiple relay servers with failover
Queue Management
Persistent queue with retry mechanisms
Load Balancing
Distribute load across multiple servers
Authentication
AUTH PLAIN and LOGIN support
TLS/SSL
Secure connections with STARTTLS
MX Routing
DNS MX record-based routing
Quick Start
Basic Relay Setup
using Zetian.Server;
using Zetian.Relay.Extensions;
// Create SMTP server with relay enabled
var server = SmtpServerBuilder
.CreateBasic()
.EnableRelay();
// Start server with relay service
var relayService = await server.StartWithRelayAsync();With Smart Host
using System.Net;
using Zetian.Server;
using Zetian.Relay.Extensions;
using Zetian.Relay.Configuration;
var server = SmtpServerBuilder
.CreateBasic()
.EnableRelay(config =>
{
config.DefaultSmartHost = new SmartHostConfiguration
{
Host = "smtp.example.com",
Port = 587,
Credentials = new NetworkCredential("user", "password"),
UseTls = true
};
});
await server.StartAsync();Advanced Configuration
Multiple Smart Hosts with Failover
Configure primary and backup smart hosts with automatic failover:
var server = SmtpServerBuilder
.CreateBasic()
.EnableRelay(config =>
{
// Primary smart host
config.DefaultSmartHost = new SmartHostConfiguration
{
Host = "primary.smtp.com",
Port = 587,
Priority = 10, // Lower priority = higher preference
Credentials = new NetworkCredential("user", "pass")
};
// Backup smart hosts
config.SmartHosts.Add(new SmartHostConfiguration
{
Host = "backup1.smtp.com",
Port = 587,
Priority = 20,
Credentials = new NetworkCredential("user", "pass")
});
config.SmartHosts.Add(new SmartHostConfiguration
{
Host = "backup2.smtp.com",
Port = 587,
Priority = 30
});
});Domain-Specific Routing
Route specific domains through different smart hosts:
var server = SmtpServerBuilder
.CreateBasic()
.EnableRelay(config =>
{
// Route specific domains through different smart hosts
config.DomainRouting["gmail.com"] = new SmartHostConfiguration
{
Host = "smtp.gmail.com",
Port = 587,
Credentials = new NetworkCredential("[email protected]", "app_password")
};
config.DomainRouting["outlook.com"] = new SmartHostConfiguration
{
Host = "smtp-mail.outlook.com",
Port = 587,
Credentials = new NetworkCredential("[email protected]", "password")
};
// Default for all other domains
config.DefaultSmartHost = new SmartHostConfiguration
{
Host = "smtp.sendgrid.net",
Port = 587,
Credentials = new NetworkCredential("apikey", "SG.xxxxx")
};
});MX-Based Routing
Use DNS MX records for automatic routing:
var server = SmtpServerBuilder
.CreateBasic()
.EnableRelay(config =>
{
// Use DNS MX records for routing
config.UseMxRouting = true;
// Optional: Custom DNS servers
config.DnsServers.Add(IPAddress.Parse("8.8.8.8"));
config.DnsServers.Add(IPAddress.Parse("1.1.1.1"));
// Fallback smart host if MX lookup fails
config.DefaultSmartHost = new SmartHostConfiguration
{
Host = "fallback.smtp.com",
Port = 25
};
});Using Relay Builder
Fluent API for comprehensive relay configuration:
using Zetian.Relay.Builder;
var relayConfig = new RelayBuilder()
.WithSmartHost("smtp.office365.com", 587, "[email protected]", "password")
.MaxConcurrentDeliveries(20)
.MaxRetries(5)
.MessageLifetime(TimeSpan.FromDays(3))
.ConnectionTimeout(TimeSpan.FromMinutes(10))
.EnableTls(true, require: true)
.LocalDomain("mail.mydomain.com")
.AddLocalDomains("mydomain.com", "internal.local")
.AddRelayDomains("partner.com", "customer.com")
.RequireAuthentication(true)
.EnableBounce(true, "[email protected]")
.Build();
var server = SmtpServerBuilder
.CreateBasic()
.EnableRelay(relayConfig);Queue Management
Manual Queue Operations
// Get relay service
var relayService = server.GetRelayService();
// Queue a message manually
var relayMessage = await server.QueueForRelayAsync(
message,
session,
RelayPriority.High);
// Get queue statistics
var stats = await server.GetRelayStatisticsAsync();
Console.WriteLine($"Queued: {stats.QueuedMessages}");
Console.WriteLine($"In Progress: {stats.InProgressMessages}");
Console.WriteLine($"Delivered: {stats.DeliveredMessages}");
Console.WriteLine($"Failed: {stats.FailedMessages}");
// Get all messages in queue
var messages = await relayService.Queue.GetAllAsync();
// Get messages by status
var deferredMessages = await relayService.Queue.GetByStatusAsync(RelayStatus.Deferred);
// Remove a message
await relayService.Queue.RemoveAsync(queueId);
// Clear expired messages
var cleared = await relayService.Queue.ClearExpiredAsync();Message Priority
server.MessageReceived += async (sender, e) =>
{
// Determine priority based on sender or content
var priority = e.Message.From?.Address?.EndsWith("@vip.com") == true
? RelayPriority.Urgent
: RelayPriority.Normal;
// Queue with priority
await server.QueueForRelayAsync(e.Message, e.Session, priority);
};Retry Configuration
Retry Settings
var server = SmtpServerBuilder
.CreateBasic()
.EnableRelay(config =>
{
// Maximum retry attempts
config.MaxRetryCount = 10;
// Message lifetime before expiration
config.MessageLifetime = TimeSpan.FromDays(4);
// Connection timeout per attempt
config.ConnectionTimeout = TimeSpan.FromMinutes(5);
// Queue processing interval
config.QueueProcessingInterval = TimeSpan.FromSeconds(30);
// Cleanup expired messages interval
config.CleanupInterval = TimeSpan.FromHours(1);
});Retry Schedule
The relay service uses exponential backoff for retries:
| Retry | Wait Time |
|---|---|
| 1st | 1 minute |
| 2nd | 2 minutes |
| 3rd | 4 minutes |
| 4th | 8 minutes |
| 5th | 16 minutes |
| 6th | 32 minutes |
| 7th+ | 1-4 hours (capped) |
Load Balancing
var server = SmtpServerBuilder
.CreateBasic()
.EnableRelay(config =>
{
// Configure multiple smart hosts with weights
config.SmartHosts.AddRange(new[]
{
new SmartHostConfiguration
{
Host = "smtp1.example.com",
Port = 25,
Priority = 10,
Weight = 50 // 50% of traffic
},
new SmartHostConfiguration
{
Host = "smtp2.example.com",
Port = 25,
Priority = 10,
Weight = 30 // 30% of traffic
},
new SmartHostConfiguration
{
Host = "smtp3.example.com",
Port = 25,
Priority = 10,
Weight = 20 // 20% of traffic
}
});
});Message Status
Queued
Message is waiting for delivery
InProgress
Message is currently being delivered
Delivered
Message successfully delivered
Failed
Permanent delivery failure
Deferred
Temporary failure, will retry
Expired
Message exceeded lifetime
Cancelled
Message was cancelled
PartiallyDelivered
Some recipients succeeded
Monitoring & Statistics
// Get comprehensive statistics
var stats = await relayService.Queue.GetStatisticsAsync();
Console.WriteLine($"Total Messages: {stats.TotalMessages}");
Console.WriteLine($"Queued: {stats.QueuedMessages}");
Console.WriteLine($"In Progress: {stats.InProgressMessages}");
Console.WriteLine($"Deferred: {stats.DeferredMessages}");
Console.WriteLine($"Delivered: {stats.DeliveredMessages}");
Console.WriteLine($"Failed: {stats.FailedMessages}");
Console.WriteLine($"Expired: {stats.ExpiredMessages}");
Console.WriteLine($"Total Size: {stats.TotalSize} bytes");
Console.WriteLine($"Oldest Message: {stats.OldestMessageTime}");
Console.WriteLine($"Average Queue Time: {stats.AverageQueueTime}");
Console.WriteLine($"Average Retry Count: {stats.AverageRetryCount}");
// Messages by priority
foreach (var kvp in stats.MessagesByPriority)
{
Console.WriteLine($"Priority {kvp.Key}: {kvp.Value} messages");
}
// Messages by smart host
foreach (var kvp in stats.MessagesBySmartHost)
{
Console.WriteLine($"Host {kvp.Key}: {kvp.Value} messages");
}Best Practices
Performance Tips
- Cache DNS MX record lookups for improved performance
- Use connection pooling to reuse SMTP client connections
- Group messages to same destination for batch delivery
- Adjust MaxConcurrentDeliveries based on resources
Security Considerations
- Always require authentication for relay access
- Use TLS/SSL for all outbound connections
- Limit relay networks to trusted IPs only
- Monitor for relay abuse and implement rate limiting