### Initialize a Basic SMTP Server Source: https://github.com/cosullivan/smtpserver/blob/master/README.md Demonstrates how to configure and start a basic SMTP server instance using SmtpServerOptionsBuilder. ```csharp var options = new SmtpServerOptionsBuilder() .ServerName("localhost") .Port(25, 587) .Build(); var smtpServer = new SmtpServer.SmtpServer(options, ServiceProvider.Default); await smtpServer.StartAsync(CancellationToken.None); ``` -------------------------------- ### Install SmtpServer via NuGet Source: https://github.com/cosullivan/smtpserver/blob/master/README.md Command to install the SmtpServer package using the NuGet Package Manager console. ```powershell PM> install-package SmtpServer ``` -------------------------------- ### Implement Custom Message Store Source: https://github.com/cosullivan/smtpserver/blob/master/README.md Example of implementing the IMessageStore interface to process and save incoming email messages. ```csharp public class SampleMessageStore : MessageStore { public override async Task SaveAsync(ISessionContext context, IMessageTransaction transaction, ReadOnlySequence buffer, CancellationToken cancellationToken) { await using var stream = new MemoryStream(); var position = buffer.GetPosition(0); while (buffer.TryGet(ref position, out var memory)) { await stream.WriteAsync(memory, cancellationToken); } stream.Position = 0; var message = await MimeKit.MimeMessage.LoadAsync(stream, cancellationToken); Console.WriteLine(message.TextBody); return SmtpResponse.Ok; } } ``` -------------------------------- ### Implement Custom User Authenticator Source: https://github.com/cosullivan/smtpserver/blob/master/README.md Example of implementing IUserAuthenticator to validate user credentials against custom logic. ```csharp public class SampleUserAuthenticator : IUserAuthenticator, IUserAuthenticatorFactory { public Task AuthenticateAsync(ISessionContext context, string user, string password, CancellationToken token) { Console.WriteLine("User={0} Password={1}", user, password); return Task.FromResult(user.Length > 4); } public IUserAuthenticator CreateInstance(ISessionContext context) { return new SampleUserAuthenticator(); } } ``` -------------------------------- ### Implement Custom Mailbox Filter Source: https://github.com/cosullivan/smtpserver/blob/master/README.md Example of implementing IMailboxFilter to control which senders are allowed and where messages can be delivered. ```csharp public class SampleMailboxFilter : IMailboxFilter, IMailboxFilterFactory { public Task CanAcceptFromAsync(ISessionContext context, IMailbox @from, int size, CancellationToken cancellationToken) { if (String.Equals(@from.Host, "test.com")) { return Task.FromResult(MailboxFilterResult.Yes); } return Task.FromResult(MailboxFilterResult.NoPermanently); } public Task CanDeliverToAsync(ISessionContext context, IMailbox to, IMailbox @from, CancellationToken token) { return Task.FromResult(MailboxFilterResult.Yes); } public IMailboxFilter CreateInstance(ISessionContext context) { return new SampleMailboxFilter(); } } ``` -------------------------------- ### Configure SMTP Server with Hooks and TLS Source: https://github.com/cosullivan/smtpserver/blob/master/README.md Shows how to configure an SMTP server with custom service providers for message storage, filtering, and authentication, including TLS certificate setup. ```csharp var options = new SmtpServerOptionsBuilder() .ServerName("localhost") .Endpoint(builder => builder .Port(9025, true) .AllowUnsecureAuthentication(false) .Certificate(CreateCertificate())) .Build(); var serviceProvider = new ServiceProvider(); serviceProvider.Add(new SampleMessageStore()); serviceProvider.Add(new SampleMailboxFilter()); serviceProvider.Add(new SampleUserAuthenticator()); var smtpServer = new SmtpServer.SmtpServer(options, serviceProvider); await smtpServer.StartAsync(CancellationToken.None); static X509Certificate2 CreateCertificate() { var certificate = File.ReadAllBytes(@"Certificate.pfx"); return new X509Certificate2(certificate, "P@ssw0rd"); } ``` -------------------------------- ### Implement and Register Custom SMTP Commands Source: https://context7.com/cosullivan/smtpserver/llms.txt This snippet demonstrates how to create a custom command factory by inheriting from SmtpCommandFactory and overriding command creation methods. It also shows how to register the factory within the .NET dependency injection container and start the SmtpServer. ```csharp using SmtpServer; using SmtpServer.Protocol; using Microsoft.Extensions.DependencyInjection; public class CustomSmtpCommandFactory : SmtpCommandFactory { public override SmtpCommand CreateEhlo(string domainOrAddress) { return new CustomEhloCommand(domainOrAddress); } public override SmtpCommand CreateHelo(string domainOrAddress) { return new CustomHeloCommand(domainOrAddress); } } public class CustomEhloCommand : EhloCommand { public CustomEhloCommand(string domainOrAddress) : base(domainOrAddress) { } protected override string GetGreeting(ISessionContext context) { return $"Welcome to {context.ServerOptions.ServerName}!"; } } public class CustomHeloCommand : HeloCommand { public CustomHeloCommand(string domainOrAddress) : base(domainOrAddress) { } } var services = new ServiceCollection(); services.AddTransient(); var options = new SmtpServerOptionsBuilder() .ServerName("mail.example.com") .Port(9025) .Build(); var server = new SmtpServer.SmtpServer(options, services.BuildServiceProvider()); await server.StartAsync(CancellationToken.None); ``` -------------------------------- ### User Authentication API Source: https://context7.com/cosullivan/smtpserver/llms.txt Implement the IUserAuthenticator interface to handle SMTP authentication, validating credentials against your user database. This example shows how to create a DatabaseUserAuthenticator and configure the server to require authentication over TLS. ```APIDOC ## IUserAuthenticator - Authenticate Users ### Description The IUserAuthenticator interface handles SMTP authentication (AUTH PLAIN, AUTH LOGIN). Implement it to validate credentials against your user database. ### Method ```csharp public override async Task AuthenticateAsync( ISessionContext context, string user, string password, CancellationToken cancellationToken) ``` ### Endpoint N/A (Interface implementation) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None (Credentials are passed as arguments) ### Request Example ```csharp // Example of configuring the server to use the authenticator var options = new SmtpServerOptionsBuilder() .ServerName("mail.example.com") .Endpoint(builder => builder .Port(587) .AuthenticationRequired(true) // Require authentication .AllowUnsecureAuthentication(false) // Only over TLS .Certificate(certificate)) .Build(); var serviceProvider = new ServiceProvider(); serviceProvider.Add(new DatabaseUserAuthenticator(userRepository)); var smtpServer = new SmtpServer.SmtpServer(options, serviceProvider); ``` ### Response #### Success Response (200) - **bool** - True if authentication is successful, false otherwise. #### Response Example ```csharp // Authentication result is returned by AuthenticateAsync method // Example of setting session properties upon successful authentication: context.Properties["AuthenticatedUser"] = user; ``` ``` -------------------------------- ### Implement IMessageStore for Email Persistence Source: https://context7.com/cosullivan/smtpserver/llms.txt Demonstrates how to implement the MessageStore class to process incoming email streams. It uses MimeKit to parse the message and provides a template for database integration. ```csharp using SmtpServer; using SmtpServer.Protocol; using SmtpServer.Storage; using System.Buffers; public class DatabaseMessageStore : MessageStore { private readonly ILogger _logger; public DatabaseMessageStore(ILogger logger) { _logger = logger; } public override async Task SaveAsync( ISessionContext context, IMessageTransaction transaction, ReadOnlySequence buffer, CancellationToken cancellationToken) { await using var stream = new MemoryStream(); var position = buffer.GetPosition(0); while (buffer.TryGet(ref position, out var memory)) { await stream.WriteAsync(memory, cancellationToken); } stream.Position = 0; var message = await MimeKit.MimeMessage.LoadAsync(stream, cancellationToken); var sender = transaction.From.AsAddress(); var recipients = transaction.To.Select(m => m.AsAddress()).ToList(); var parameters = transaction.Parameters; _logger.LogInformation("Received message from {Sender} to {Recipients}, Subject: {Subject}", sender, string.Join(", ", recipients), message.Subject); await SaveToDatabase(message, sender, recipients, cancellationToken); return SmtpResponse.Ok; } private Task SaveToDatabase(MimeKit.MimeMessage message, string sender, List recipients, CancellationToken ct) { return Task.CompletedTask; } } var serviceProvider = new ServiceProvider(); serviceProvider.Add(new DatabaseMessageStore(logger)); ``` -------------------------------- ### Configure Secure Endpoints with TLS Source: https://context7.com/cosullivan/smtpserver/llms.txt Shows how to define secure listening endpoints using EndpointDefinitionBuilder, including SSL/TLS protocol settings and certificate management for secure email submission. ```csharp using SmtpServer; using System.Security.Authentication; using System.Security.Cryptography.X509Certificates; var options = new SmtpServerOptionsBuilder() .ServerName("secure-mail.example.com") .Endpoint(builder => builder .Port(465, true) .IsSecure(true) .AuthenticationRequired(true) .AllowUnsecureAuthentication(false) .SessionTimeout(TimeSpan.FromMinutes(5)) .SupportedSslProtocols(SslProtocols.Tls12 | SslProtocols.Tls13) .Certificate(new X509Certificate2("certificate.pfx", "password"))) .Endpoint(builder => builder .Port(587) .AllowUnsecureAuthentication(false) .Certificate(new X509Certificate2("certificate.pfx", "password"))) .Build(); var smtpServer = new SmtpServer.SmtpServer(options, ServiceProvider.Default); await smtpServer.StartAsync(CancellationToken.None); ``` -------------------------------- ### Monitor Server Activity with Session Events Source: https://context7.com/cosullivan/smtpserver/llms.txt Shows how to subscribe to session lifecycle events such as creation, command execution, and completion to log activity and track session metrics. ```csharp using SmtpServer; using SmtpServer.ComponentModel; using SmtpServer.Tracing; using SmtpServer.Net; var options = new SmtpServerOptionsBuilder() .ServerName("mail.example.com") .Port(9025) .Build(); var server = new SmtpServer.SmtpServer(options, ServiceProvider.Default); server.SessionCreated += (sender, args) => { var sessionId = args.Context.SessionId; Console.WriteLine($"Session {sessionId} created"); args.Context.Properties["StartTime"] = DateTime.UtcNow; args.Context.CommandExecuting += (s, e) => { Console.WriteLine($"Executing command: {e.Command.GetType().Name}"); new TracingSmtpCommandVisitor(Console.Out).Visit(e.Command); }; args.Context.CommandExecuted += (s, e) => { Console.WriteLine($"Completed command: {e.Command.GetType().Name}"); }; }; server.SessionCompleted += (sender, args) => { var endpoint = args.Context.Properties[EndpointListener.RemoteEndPointKey]; var duration = DateTime.UtcNow - (DateTime)args.Context.Properties["StartTime"]; Console.WriteLine($"Session completed from {endpoint}, duration: {duration}"); }; await server.StartAsync(CancellationToken.None); ``` -------------------------------- ### Perform Graceful Server Shutdown Source: https://context7.com/cosullivan/smtpserver/llms.txt Illustrates how to stop accepting new connections while allowing existing sessions to finish, ensuring no messages are lost during the shutdown process. ```csharp var cancellationTokenSource = new CancellationTokenSource(); var options = new SmtpServerOptionsBuilder().ServerName("mail.example.com").Port(9025).Build(); var server = new SmtpServer.SmtpServer(options, ServiceProvider.Default); var serverTask = server.StartAsync(cancellationTokenSource.Token); Console.CancelKeyPress += async (sender, args) => { args.Cancel = true; Console.WriteLine("Initiating graceful shutdown..."); server.Shutdown(); await server.ShutdownTask; Console.WriteLine("No longer accepting new connections"); await serverTask; Console.WriteLine("All sessions completed, server stopped"); }; await serverTask; ``` -------------------------------- ### Implement IUserAuthenticator for SMTP Authentication Source: https://context7.com/cosullivan/smtpserver/llms.txt Demonstrates how to create a custom user authenticator by extending UserAuthenticator and configuring the SmtpServer to use it for credential validation. ```csharp using SmtpServer; using SmtpServer.Authentication; public class DatabaseUserAuthenticator : UserAuthenticator { private readonly IUserRepository _userRepository; public DatabaseUserAuthenticator(IUserRepository userRepository) { _userRepository = userRepository; } public override async Task AuthenticateAsync( ISessionContext context, string user, string password, CancellationToken cancellationToken) { var isValid = await _userRepository.ValidateCredentialsAsync(user, password, cancellationToken); if (isValid) { context.Properties["AuthenticatedUser"] = user; Console.WriteLine($"User {user} authenticated successfully"); } else { Console.WriteLine($"Authentication failed for user {user}"); } return isValid; } } var options = new SmtpServerOptionsBuilder() .ServerName("mail.example.com") .Endpoint(builder => builder .Port(587) .AuthenticationRequired(true) .AllowUnsecureAuthentication(false) .Certificate(certificate)) .Build(); var serviceProvider = new ServiceProvider(); serviceProvider.Add(new DatabaseUserAuthenticator(userRepository)); var smtpServer = new SmtpServer.SmtpServer(options, serviceProvider); ``` -------------------------------- ### Configure SmtpServer Options Source: https://github.com/cosullivan/smtpserver/blob/master/CHANGELOG.md This C# code snippet demonstrates how to configure SmtpServer options, including setting the server name, maximum message size with a specified handling strategy, and command wait timeout. It utilizes the SmtpServerOptionsBuilder for fluent configuration. ```cs var options = new SmtpServerOptionsBuilder() .ServerName("My mail server") .MaxMessageSize(5242880, MaxMessageSizeHandling.Strict) //5MB .CommandWaitTimeout(TimeSpan.FromSeconds(60)) ``` -------------------------------- ### Integrate SmtpServer with Dependency Injection Source: https://context7.com/cosullivan/smtpserver/llms.txt Demonstrates how to register SmtpServer and its related services (message store, mailbox filter, user authenticator) with Microsoft.Extensions.DependencyInjection. This allows SmtpServer to be managed by the IoC container and used in applications like ASP.NET Core. It registers custom implementations for storage and filtering, configures SmtpServer options, and registers it as a singleton, along with a hosted service to manage its lifecycle. ```csharp using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using SmtpServer; using SmtpServer.Storage; public class Program { public static void Main(string[] args) { Host.CreateDefaultBuilder(args) .ConfigureServices((context, services) => { // Register custom implementations services.AddTransient(); services.AddTransient(); services.AddTransient(); // Register SmtpServer as singleton services.AddSingleton(provider => { var options = new SmtpServerOptionsBuilder() .ServerName("mail.example.com") .Port(9025) .Build(); return new SmtpServer.SmtpServer(options, provider); }); // Register as hosted service services.AddHostedService(); }) .Build() .Run(); } } public class SmtpServerHostedService : BackgroundService { private readonly SmtpServer.SmtpServer _smtpServer; public SmtpServerHostedService(SmtpServer.SmtpServer smtpServer) { _smtpServer = smtpServer; } protected override Task ExecuteAsync(CancellationToken stoppingToken) { return _smtpServer.StartAsync(stoppingToken); } } ``` -------------------------------- ### Handle Custom SMTP Responses with SmtpResponseException Source: https://context7.com/cosullivan/smtpserver/llms.txt Illustrates how to customize SMTP server responses to clients using `SmtpResponse` constants or by throwing `SmtpResponseException`. This allows for immediate error reporting with specific SMTP reply codes and messages, and optionally terminates the client session. It also shows how to include custom metadata in exceptions for logging purposes. ```csharp using SmtpServer.Protocol; using SmtpServer.Storage; public class StrictMailboxFilter : MailboxFilter { public override Task CanAcceptFromAsync( ISessionContext context, IMailbox from, int size, CancellationToken ct) { // Use predefined responses if (from == Mailbox.Empty) { throw new SmtpResponseException(SmtpResponse.MailboxNameNotAllowed); } // Custom response with specific code and message if (from.Host == "blocked.com") { throw new SmtpResponseException( new SmtpResponse(SmtpReplyCode.MailboxUnavailable, "Domain blocked")); } // Terminate session immediately if (from.Host == "malicious.com") { throw new SmtpResponseException( new SmtpResponse(SmtpReplyCode.TransactionFailed, "Connection refused"), quit: true); // Close connection } // Include metadata for logging if (size > 50 * 1024 * 1024) { var properties = new Dictionary { ["RequestedSize"] = size, ["MaxAllowed"] = 50 * 1024 * 1024 }; throw new SmtpResponseException( SmtpResponse.SizeLimitExceeded, quit: false, properties: properties); } return Task.FromResult(true); } } // Available SmtpResponse constants: // SmtpResponse.Ok - 250 Ok // SmtpResponse.ServiceReady - 220 Service ready // SmtpResponse.ServiceClosingTransmissionChannel - 221 Bye // SmtpResponse.AuthenticationSuccessful - 235 Authentication successful // SmtpResponse.AuthenticationFailed - 535 Authentication failed // SmtpResponse.AuthenticationRequired - 530 Authentication required // SmtpResponse.MailboxUnavailable - 550 Mailbox unavailable // SmtpResponse.MailboxNameNotAllowed - 553 Mailbox name not allowed // SmtpResponse.SyntaxError - 501 Syntax error // SmtpResponse.SizeLimitExceeded - 552 Size limit exceeded // SmtpResponse.TransactionFailed - 554 Transaction failed // SmtpResponse.BadSequence - 503 Bad sequence of commands ``` -------------------------------- ### Implement IMailboxFilter for Validation Source: https://context7.com/cosullivan/smtpserver/llms.txt Shows how to create a custom MailboxFilter to validate senders and recipients. It includes logic for domain allowlisting, sender blocklisting, and message size enforcement. ```csharp using SmtpServer; using SmtpServer.Mail; using SmtpServer.Protocol; using SmtpServer.Storage; using SmtpServer.Net; using System.Net; public class DomainMailboxFilter : MailboxFilter { private readonly HashSet _allowedDomains = new() { "example.com", "trusted.org" }; private readonly HashSet _blockedSenders = new() { "spam@bad.com" }; public override Task CanAcceptFromAsync(ISessionContext context, IMailbox from, int size, CancellationToken cancellationToken) { if (from == Mailbox.Empty) { throw new SmtpResponseException(SmtpResponse.MailboxNameNotAllowed); } var address = $"{from.User}@{from.Host}".ToLowerInvariant(); if (_blockedSenders.Contains(address)) { throw new SmtpResponseException(new SmtpResponse(SmtpReplyCode.MailboxUnavailable, "Sender blocked")); } if (size > 10 * 1024 * 1024) { throw new SmtpResponseException(SmtpResponse.SizeLimitExceeded); } var endpoint = (IPEndPoint)context.Properties[EndpointListener.RemoteEndPointKey]; Console.WriteLine($"Connection from: {endpoint.Address}"); return Task.FromResult(true); } public override Task CanDeliverToAsync(ISessionContext context, IMailbox to, IMailbox from, CancellationToken cancellationToken) { if (!_allowedDomains.Contains(to.Host.ToLowerInvariant())) { throw new SmtpResponseException(new SmtpResponse(SmtpReplyCode.MailboxUnavailable, $"Relay denied for domain {to.Host}")); } return Task.FromResult(true); } } var serviceProvider = new ServiceProvider(); serviceProvider.Add(new DomainMailboxFilter()); ``` -------------------------------- ### Session Events API Source: https://context7.com/cosullivan/smtpserver/llms.txt SmtpServer provides events to monitor session lifecycle and command execution for logging, metrics, and debugging. Subscribe to these events to gain insights into server activity. ```APIDOC ## Session Events - Monitor Server Activity ### Description SmtpServer provides events to monitor session lifecycle and command execution for logging, metrics, and debugging. ### Method Event subscriptions on the `SmtpServer` instance. ### Endpoint N/A (Event-driven) ### Parameters None ### Request Example ```csharp var options = new SmtpServerOptionsBuilder() .ServerName("mail.example.com") .Port(9025) .Build(); var server = new SmtpServer.SmtpServer(options, ServiceProvider.Default); // Session lifecycle events server.SessionCreated += (sender, args) => { var sessionId = args.Context.SessionId; Console.WriteLine($"Session {sessionId} created"); // Add custom session properties args.Context.Properties["StartTime"] = DateTime.UtcNow; // Subscribe to command events for this session args.Context.CommandExecuting += (s, e) => { Console.WriteLine($"Executing command: {e.Command.GetType().Name}"); new TracingSmtpCommandVisitor(Console.Out).Visit(e.Command); }; args.Context.CommandExecuted += (s, e) => { Console.WriteLine($"Completed command: {e.Command.GetType().Name}"); }; args.Context.ResponseException += (s, e) => { Console.WriteLine($"Response exception: {e.Exception.Response.Message}"); }; args.Context.SessionAuthenticated += (s, e) => { Console.WriteLine($"Session authenticated: {args.Context.Authentication.User}"); }; }; server.SessionCompleted += (sender, args) => { var endpoint = args.Context.Properties[EndpointListener.RemoteEndPointKey]; var duration = DateTime.UtcNow - (DateTime)args.Context.Properties["StartTime"]; Console.WriteLine($"Session completed from {endpoint}, duration: {duration}"); }; server.SessionFaulted += (sender, args) => { Console.WriteLine($"Session faulted: {args.Exception.Message}"); }; server.SessionCancelled += (sender, args) => { Console.WriteLine($"Session cancelled: {args.Context.SessionId}"); }; await server.StartAsync(CancellationToken.None); ``` ### Response Events are triggered asynchronously based on server activity. #### Success Response (200) N/A #### Response Example Console output demonstrating event handling. ``` -------------------------------- ### Graceful Shutdown API Source: https://context7.com/cosullivan/smtpserver/llms.txt Use the Shutdown method to stop accepting new connections while allowing active sessions to complete, ensuring no messages are lost during shutdown. This is crucial for maintaining service availability during maintenance or restarts. ```APIDOC ## Graceful Shutdown - Stop Server Without Losing Messages ### Description Use the Shutdown method to stop accepting new connections while allowing active sessions to complete, ensuring no messages are lost during shutdown. ### Method ```csharp server.Shutdown(); await server.ShutdownTask; ``` ### Endpoint N/A (Server control operation) ### Parameters None ### Request Example ```csharp var cancellationTokenSource = new CancellationTokenSource(); var options = new SmtpServerOptionsBuilder() .ServerName("mail.example.com") .Port(9025) .Build(); var server = new SmtpServer.SmtpServer(options, ServiceProvider.Default); var serverTask = server.StartAsync(cancellationTokenSource.Token); // Handle shutdown signal (e.g., SIGTERM, Ctrl+C) Console.CancelKeyPress += async (sender, args) => { args.Cancel = true; // Prevent immediate termination Console.WriteLine("Initiating graceful shutdown..."); // Stop accepting new connections server.Shutdown(); // Wait for listeners to stop await server.ShutdownTask; Console.WriteLine("No longer accepting new connections"); // Wait for active sessions to complete await serverTask; Console.WriteLine("All sessions completed, server stopped"); }; await serverTask; ``` ### Response N/A (Server stops accepting connections and existing sessions complete.) #### Success Response (200) N/A #### Response Example Console output indicating shutdown progress and completion. ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.