Zetian.Relay 1.0.5

Prefix Reserved
dotnet add package Zetian.Relay --version 1.0.5
                    
NuGet\Install-Package Zetian.Relay -Version 1.0.5
                    
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.Relay" Version="1.0.5" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Zetian.Relay" Version="1.0.5" />
                    
Directory.Packages.props
<PackageReference Include="Zetian.Relay" />
                    
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.Relay --version 1.0.5
                    
#r "nuget: Zetian.Relay, 1.0.5"
                    
#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.Relay@1.0.5
                    
#: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.Relay&version=1.0.5
                    
Install as a Cake Addin
#tool nuget:?package=Zetian.Relay&version=1.0.5
                    
Install as a Cake Tool

Zetian.Relay - SMTP Relay and Proxy Extension

NuGet-Version NuGet-Download License

SMTP relay and proxy extension for Zetian SMTP Server with smart host support, queue management, load balancing, and failover mechanisms.

⚡ Features

  • 🎚️ Priority Queuing - Message priority support
  • 📊 MX Routing - DNS MX record-based routing
  • 🔀 Failover - Automatic failover to backup servers
  • 📈 Queue Statistics - Real-time queue monitoring
  • 💌 Bounce Messages - Automatic NDR generation
  • 🎯 Domain Routing - Custom routing rules per domain
  • 🌐 TLS/SSL - Secure connections with STARTTLS support
  • 🔐 Authentication - Support for AUTH PLAIN and LOGIN
  • ⏱️ Retry Logic - Exponential backoff with configurable limits
  • ⚖️ Load Balancing - Distribute load across multiple relay servers
  • 🔄 Queue Management - Persistent queue with retry mechanisms
  • 📬 Smart Host Support - Route messages through configured relay servers

📦 Installation

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

# Install Relay Extension
dotnet add package Zetian.Relay

🚀 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();

Multiple Smart Hosts with Failover

var server = SmtpServerBuilder
    .CreateBasic()
    .EnableRelay(config =>
{
    // Primary smart host
    config.DefaultSmartHost = new SmartHostConfiguration
    {
        Host = "primary.smtp.com",
        Port = 587,
        Priority = 10,
        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
    });
});

🎯 Advanced Configuration

Using Relay Builder

using Zetian.Server;
using Zetian.Relay.Builder;
using Zetian.Relay.Extensions;

var relayConfig = new RelayBuilder()
    .WithSmartHost("smtp.office365.com", 587, "user@domain.com", "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, "postmaster@mydomain.com")
    .Build();

var server = SmtpServerBuilder
    .CreateBasic()
    .EnableRelay(relayConfig);

Domain-Specific Routing

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("user@gmail.com", "app_password")
    };
    
    config.DomainRouting["outlook.com"] = new SmartHostConfiguration
    {
        Host = "smtp-mail.outlook.com",
        Port = 587,
        Credentials = new NetworkCredential("user@outlook.com", "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

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
    };
});

Relay Networks Configuration

var server = SmtpServerBuilder
    .CreateBasic()
    .EnableRelay(config =>
{
    // Allow relay from specific IP addresses without authentication
    config.RelayNetworks.Add(IPAddress.Parse("192.168.1.0"));
    config.RelayNetworks.Add(IPAddress.Parse("10.0.0.0"));
    
    // Require authentication for all others
    config.RequireAuthentication = true;
});

📊 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

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:

  • 1st retry: 1 minute
  • 2nd retry: 2 minutes
  • 3rd retry: 4 minutes
  • 4th retry: 8 minutes
  • 5th retry: 16 minutes
  • 6th retry: 32 minutes
  • 7th+ retry: 1-4 hours (capped)

📬 Bounce Messages

var server = SmtpServerBuilder
    .CreateBasic()
    .EnableRelay(config =>
{
    // Enable bounce message generation
    config.EnableBounceMessages = true;
    
    // Set bounce sender address
    config.BounceSender = "postmaster@mydomain.com";
    
    // Enable delivery status notifications
    config.EnableDsn = true;
});

🔐 Authentication Methods

AUTH PLAIN

var smartHost = new SmartHostConfiguration
{
    Host = "smtp.example.com",
    Port = 587,
    Credentials = new NetworkCredential("username", "password"),
    UseStartTls = true
};

AUTH LOGIN

The relay client automatically detects and uses the appropriate authentication method based on server capabilities.

📈 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
        }
    });
});

🌐 TLS/SSL Configuration

var server = SmtpServerBuilder
    .CreateBasic()
    .EnableRelay(config =>
{
    // Enable TLS for outbound connections
    config.EnableTls = true;
    
    // Require TLS (fail if not available)
    config.RequireTls = true;
    
    // Configure SSL protocols
    config.SslProtocols = SslProtocols.Tls12 | SslProtocols.Tls13;
    
    // Validate server certificates
    config.ValidateServerCertificate = true;
});

🎛️ Extension Methods

// Create server first
var server = SmtpServerBuilder
    .CreateBasic()
    .EnableRelay();

// Add smart host
server.AddSmartHost("smtp.gmail.com", 587, 
    new NetworkCredential("user", "pass"));

// Set relay domains
server.SetRelayDomains("external.com", "partner.org");

// Set local domains (not relayed)
server.SetLocalDomains("mydomain.com", "internal.local");

// Add relay network
server.AddRelayNetwork(IPAddress.Parse("192.168.1.0"));

// Get relay statistics
var stats = await server.GetRelayStatisticsAsync();

// Get relay service
var relayService = server.GetRelayService();

🔍 Message Status

Status Description
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

// 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");
}

🚀 Performance Tips

  1. DNS Caching - Cache MX record lookups
  2. Connection Pooling - Reuse SMTP client connections
  3. Message Batching - Group messages to same destination
  4. Queue Persistence - Consider persistent queue for reliability
  5. Smart Host Selection - Use priority and weight for optimal routing
  6. Concurrent Deliveries - Adjust MaxConcurrentDeliveries based on resources

📚 Best Practices

  1. Log Relay Activity - Audit trail for compliance
  2. Implement Rate Limiting - Prevent abuse of relay
  3. Monitor Queue Size - Prevent unbounded growth
  4. Use TLS When Possible - Secure message transmission
  5. Configure Bounce Handling - Inform senders of failures
  6. Regular Cleanup - Remove expired messages periodically
  7. Set Message Lifetime - Clean up undeliverable messages
  8. Always Configure Timeouts - Prevent hanging connections

🔒 Security Considerations

  • Regular security audits
  • Monitor for relay abuse
  • Implement rate limiting
  • Validate server certificates
  • Limit relay networks to trusted IPs
  • Use TLS/SSL for all outbound connections
  • Always require authentication for relay access

📋 Requirements

  • Windows, Linux, or macOS
  • .NET 6.0, 7.0, 8.0, 9.0, or 10.0
  • Zetian SMTP Server package

📚 Documentation & Support

📄 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.5 683 12/1/2025
1.0.4 132 11/1/2025
1.0.3 205 10/29/2025
1.0.2 205 10/29/2025
1.0.1 229 10/29/2025
1.0.0 304 10/29/2025

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