Documentation/Authentication

Authentication and Security

Make your SMTP server secure and add user authentication.

Security is Top Priority

Zetian supports modern security standards: TLS 1.2/1.3, STARTTLS, multiple authentication mechanisms and customizable auth handlers.

Basic Authentication

Authentication with simple username and password:

Authentication.cs
using Zetian;
using Zetian.Authentication;

// Simple username/password authentication
var server = new SmtpServerBuilder()
    .Port(587)
    .RequireAuthentication()
    .AllowPlainTextAuthentication()
    .SimpleAuthentication("admin", "password123")
    .Build();

// For multiple users
var users = new Dictionary<string, string>
{
    ["admin"] = "admin123",
    ["user1"] = "pass123",
    ["demo"] = "demo123"
};

var server = new SmtpServerBuilder()
    .Port(587)
    .RequireAuthentication()
    .AllowPlainTextAuthentication()
    .AuthenticationHandler(async (username, password) =>
    {
        if (users.TryGetValue(username, out var correctPassword) && 
            password == correctPassword)
        {
            return AuthenticationResult.Succeed(username);
        }
        return AuthenticationResult.Fail("Invalid credentials");
    })
    .Build();

Custom Authentication

Integration with database or external systems:

DatabaseAuthHandler.cs
// Custom authentication handler with database
public class DatabaseAuthHandler
{
    private readonly IUserRepository _userRepository;
    
    public DatabaseAuthHandler(IUserRepository userRepository)
    {
        _userRepository = userRepository;
    }
    
    // AuthenticationHandler delegate signature: (string?, string?) => Task<AuthenticationResult>
    public async Task<AuthenticationResult> AuthenticateAsync(
        string? username, 
        string? password)
    {
        if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password))
        {
            return AuthenticationResult.Fail("Username and password required");
        }
        
        // Get user from database
        var user = await _userRepository.GetByUsernameAsync(username);
        
        if (user == null)
        {
            return AuthenticationResult.Fail("User not found");
        }
        
        // Check password hash (use BCrypt in production)
        // Install: dotnet add package BCrypt.Net-Next
        // if (!BCrypt.Net.BCrypt.Verify(password, user.PasswordHash))
        if (password != user.PasswordHash) // Don't use plain text in production!
        {
            return AuthenticationResult.Fail("Invalid password");
        }
        
        // Is account active?
        if (!user.IsActive)
        {
            return AuthenticationResult.Fail("Account is disabled");
        }
        
        // Successful authentication
        // Note: AuthenticationResult.Succeed only takes username
        return AuthenticationResult.Succeed(username);
    }
}

// Usage
var userRepository = new YourUserRepository(); // Your database implementation
var authHandler = new DatabaseAuthHandler(userRepository);

var server = new SmtpServerBuilder()
    .Port(587)
    .RequireAuthentication()
    .AllowPlainTextAuthentication() // For testing without TLS
    .AuthenticationHandler(authHandler.AuthenticateAsync)
    .Build();

Database Integration

SQL, NoSQL or any data source

Password Hashing

BCrypt, Argon2 or other hash algorithms

Account Status

Active/passive account check, role-based access

TLS/SSL Security

TLS/SSL configuration for encrypted connections:

TlsConfiguration.cs
// Secure connection with TLS/SSL
var server = new SmtpServerBuilder()
    .Port(587)
    .Certificate("certificate.pfx", "certificate_password")
    .RequireSecureConnection() // TLS required
    .RequireAuthentication()   // Auth required
    .Build();

// Allow plain text authentication (for testing without TLS)
var testServer = new SmtpServerBuilder()
    .Port(587)
    .RequireAuthentication()
    .AllowPlainTextAuthentication() // Allow auth without TLS
    .SimpleAuthentication("admin", "password")
    .Build();

// SSL/TLS with certificate object
var cert = new X509Certificate2("certificate.pfx", "password");
var server = new SmtpServerBuilder()
    .Port(465)
    .Certificate(cert)
    .RequireSecureConnection()
    .RequireAuthentication()
    .Build();

STARTTLS (Port 587)

Initially plain text, transition to encryption with STARTTLS command.

  • • Recommended for modern email clients
  • • Backward compatible
  • • Flexible security

Implicit TLS (Port 465)

Fully encrypted from the beginning of connection.

  • • Maximum security
  • • Old standard but still in use
  • • Known as SMTPS

Authentication Mechanisms

Supported authentication mechanisms and events:

AuthMechanisms.cs
// Different authentication mechanisms
var server = new SmtpServerBuilder()
    .Port(587)
    .RequireAuthentication()
    .AllowPlainTextAuthentication() // Allow auth without TLS
    // Add authentication mechanisms
    .AddAuthenticationMechanism("PLAIN")   // Default
    .AddAuthenticationMechanism("LOGIN")   // Legacy support
    // Custom authentication handler for all mechanisms
    .AuthenticationHandler(async (username, password) =>
    {
        // Your authentication logic here
        return AuthenticationResult.Succeed(username);
    })
    .Build();

// Authentication tracking via session events
server.SessionCompleted += (sender, e) =>
{
    if (e.Session.IsAuthenticated)
    {
        Console.WriteLine($"User session completed: {e.Session.AuthenticatedIdentity}");
    }
};

// Message from authenticated user
server.MessageReceived += (sender, e) =>
{
    if (e.Session.IsAuthenticated)
    {
        Console.WriteLine($"Message from authenticated user: {e.Session.AuthenticatedIdentity}");
    }
};

PLAIN

Base64 encoded username and password

LOGIN

Legacy type, Microsoft Outlook compatible

CRAM-MD5

Challenge-response based (optional)

SMTP Authentication Flow

A typical SMTP authentication session:

AuthenticationFlow.cs
// Authentication flow
// 1. Client: Sends AUTH PLAIN command
// 2. Server: Continues with 334 response
// 3. Client: Sends Base64 encoded credentials
// 4. Server: Validates and responds

// Example SMTP session:
C: EHLO client.example.com
S: 250-smtp.example.com
S: 250-AUTH PLAIN LOGIN
S: 250 STARTTLS

C: STARTTLS
S: 220 Ready to start TLS
[TLS handshake]

C: EHLO client.example.com
S: 250-smtp.example.com
S: 250 AUTH PLAIN LOGIN

C: AUTH PLAIN
S: 334
C: AGFkbWluAHBhc3N3b3JkMTIz
S: 235 Authentication successful

// Now can send mail
C: MAIL FROM:<[email protected]>
S: 250 OK

Security Tip

PLAIN and LOGIN mechanisms encode passwords with Base64 but do not encrypt. Therefore, they must be used with TLS/SSL.