SMTP relay and proxy extension for Zetian SMTP Server. Features include smart host support, queue management, load balancing, and failover mechanisms.
$ dotnet add package Zetian.RelaySMTP relay and proxy extension for Zetian SMTP Server with smart host support, queue management, load balancing, and failover mechanisms.
# Install Zetian SMTP Server (required)
dotnet add package Zetian
# Install Relay Extension
dotnet add package Zetian.Relay
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();
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();
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
});
});
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);
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")
};
});
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
};
});
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;
});
// 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();
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);
};
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);
});
The relay service uses exponential backoff for retries:
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;
});
var smartHost = new SmartHostConfiguration
{
Host = "smtp.example.com",
Port = 587,
Credentials = new NetworkCredential("username", "password"),
UseStartTls = true
};
The relay client automatically detects and uses the appropriate authentication method based on server capabilities.
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
}
});
});
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;
});
// 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();
| 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 |
// 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");
}
MaxConcurrentDeliveries based on resourcesMIT License - see LICENSE
Built with ❤️ for the .NET community