diff --git a/src/Zetian.Relay/Client/SmtpRelayClient.cs b/src/Zetian.Relay/Client/SmtpRelayClient.cs index 894b5d3..02420dd 100644 --- a/src/Zetian.Relay/Client/SmtpRelayClient.cs +++ b/src/Zetian.Relay/Client/SmtpRelayClient.cs @@ -16,6 +16,7 @@ using Zetian.Protocol; using Zetian.Relay.Abstractions; using Zetian.Relay.Models; +using Zetian.Relay.Services; namespace Zetian.Relay.Client { @@ -62,13 +63,27 @@ public async Task ConnectAsync(CancellationToken cancellationToken = default) using CancellationTokenSource cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); cts.CancelAfter(Timeout); - await _tcpClient.ConnectAsync(Host, Port).ConfigureAwait(false); + await _tcpClient.ConnectAsync(Host, Port, cts.Token).ConfigureAwait(false); _stream = _tcpClient.GetStream(); if (EnableSsl) { - await UpgradeToSslAsync(cts.Token).ConfigureAwait(false); + try + { + await UpgradeToSslAsync(cts.Token).ConfigureAwait(false); + } + catch (Exception) + { + _logger.LogInformation("Failed to connect as SMTPS on {Host}:{Port}", Host, Port); + + _stream.Close(); + await _stream.DisposeAsync(); + + _tcpClient = new TcpClient(); + await _tcpClient.ConnectAsync(Host, Port, cts.Token).ConfigureAwait(false); + _stream = _tcpClient.GetStream(); + } } _reader = new StreamReader(_stream, Encoding.ASCII); @@ -84,6 +99,15 @@ public async Task ConnectAsync(CancellationToken cancellationToken = default) // Send EHLO await SendEhloAsync(cts.Token).ConfigureAwait(false); + // Upgrade the connection to STARTTLS if allowed + if (EnableSsl && _stream is not SslStream && _serverCapabilities?.ContainsKey("STARTTLS") == true) + { + await UpgradeToStartTlsAsync(cts.Token).ConfigureAwait(false); + + _reader = new StreamReader(_stream, Encoding.ASCII); + _writer = new StreamWriter(_stream, Encoding.ASCII) { AutoFlush = true }; + } + _logger.LogInformation("Connected to {Host}:{Port}", Host, Port); } catch (Exception ex) @@ -398,6 +422,18 @@ await sslStream.AuthenticateAsClientAsync( _logger.LogDebug("SSL/TLS connection established"); } + private async Task UpgradeToStartTlsAsync(CancellationToken cancellationToken) + { + await SendCommandAsync("STARTTLS", cancellationToken).ConfigureAwait(false); + + SmtpResponse response = await ReadResponseAsync(cancellationToken).ConfigureAwait(false); + + if (response.IsSuccess) + { + await UpgradeToSslAsync(cancellationToken); + } + } + private async Task AuthPlainAsync(CancellationToken cancellationToken) { if (Credentials == null) diff --git a/src/Zetian.Relay/Services/RelayService.cs b/src/Zetian.Relay/Services/RelayService.cs index 643bc0d..613e905 100644 --- a/src/Zetian.Relay/Services/RelayService.cs +++ b/src/Zetian.Relay/Services/RelayService.cs @@ -426,6 +426,11 @@ private async Task CanRelayAsync(ISmtpSession session, ISmtpMessage messag return config; } + if (Configuration.DefaultSmartHost?.Host == host && Configuration.DefaultSmartHost?.Port == port) + { + return Configuration.DefaultSmartHost; + } + // Create default configuration return new SmartHostConfiguration {