SmtpServer .NET Documentation

repository·master·Indexed 21 days ago

https://github.com/cosullivan/smtpserver

A lightweight, high-performance SMTP server implementation for .NET built using the Task Parallel Library (TPL). It features an extensible hook-based system for message storage (IMessageStore), mailbox filtering (IMailboxFilter), and authentication (IUserAuthenticator).

Tokens
1.9K
Snippets
6
Records
6
Agent score
24%

What's inside SmtpServer

  1. Implement custom hooks for SmtpServer

    master

    SmtpServer allows you to extend its behavior by implementing three primary hooks via a ServiceProvider. You must register these implementations in your ServiceProvider before passing it to the SmtpServer constructor.

    Supported hooks:

    • IMessageStore: Handles saving or processing incoming messages.
    • IMailboxFilter: Determines if a sender is allowed or if a message can be delivered to a specific mailbox.
    • IUserAuthenticator: Handles user authentication logic.

    Note: For hooks that require factory patterns (like IMailboxFilter or IUserAuthenticator), you should also implement the corresponding factory interface (e.g., IMailboxFilterFactory) to allow the server to create new instances per session.

    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);
  2. Get started with a basic SMTP server

    master

    To start a minimal SMTP server, use SmtpServerOptionsBuilder to configure the server name and ports, then instantiate SmtpServer.SmtpServer using ServiceProvider.Default for basic dependency injection.

    var options = new SmtpServerOptionsBuilder()
        .ServerName("localhost")
        .Port(25, 587)
        .Build();
    
    var smtpServer = new SmtpServer.SmtpServer(options, ServiceProvider.Default);
    await smtpServer.StartAsync(CancellationToken.None);
  3. Implement IMessageStore to process messages

    master

    Implement IMessageStore (or inherit from MessageStore) to intercept the raw message buffer. The SaveAsync method provides access to the ISessionContext, the IMessageTransaction, and a ReadOnlySequence<byte> containing the message data.

    public class SampleMessageStore : MessageStore
    {
        public override async Task<SmtpResponse> SaveAsync(ISessionContext context, IMessageTransaction transaction, ReadOnlySequence<byte> 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;
        }
    }
  4. Implement IMailboxFilter to control mail flow

    master

    Implement IMailboxFilter and IMailboxFilterFactory to control which senders are allowed and which recipients can receive mail.

    • CanAcceptFromAsync: Returns a MailboxFilterResult. Use MailboxFilterResult.Yes to allow or MailboxFilterResult.NoPermanently to reject.
    • CanDeliverToAsync: Determines if a message can be delivered to a specific recipient.
    • CreateInstance: Required by the factory interface to provide a new filter instance for the session.
    public class SampleMailboxFilter : IMailboxFilter, IMailboxFilterFactory
    {
        public Task<MailboxFilterResult> 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<MailboxFilterResult> CanDeliverToAsync(ISessionContext context, IMailbox to, IMailbox @from, CancellationToken token)
        {
            return Task.FromResult(MailboxFilterResult.Yes);
        }
    
        public IMailboxFilter CreateInstance(ISessionContext context)
        {
            return new SampleMailboxFilter();
        }
    }
  5. Implement IUserAuthenticator for user login

    master

    Implement IUserAuthenticator and IUserAuthenticatorFactory to handle SMTP authentication (e.g., AUTH PLAIN or LOGIN).

    • AuthenticateAsync: Validates the provided user and password. Returns true if authentication succeeds, false otherwise.
    • CreateInstance: Required by the factory interface to provide a new authenticator instance for the session.
    public class SampleUserAuthenticator : IUserAuthenticator, IUserAuthenticatorFactory
    {
        public Task<bool> 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();
        }
    }