Zetian.Relay

Advanced SMTP Relay and Proxy Extension for Zetian

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:

RetryWait Time
1st1 minute
2nd2 minutes
3rd4 minutes
4th8 minutes
5th16 minutes
6th32 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