public async Task SendAsync(EmailConfig.OutgoingConfig config, IMailMessage message, CancellationToken cancellationToken = default) { var mailMessage = message.ToMailKitMessage(); await ConnectAsync(_client, config, cancellationToken); _log.LogInformation(Message.SendInfo, message, config); await Policy.Handle <SocketException>() .WaitAndRetryAsync(_retryConfig.Max, _ => _retryConfig.Delay, (exception, ts) => _log.LogError(exception, $"Error sending mail, retrying in {ts}.")) .ExecuteAsync(token => _client.SendAsync(mailMessage, token), cancellationToken); await _client.DisconnectAsync(true, cancellationToken); }
public async Task WhenOneOfUsernameOrPasswordNotProvidedThenItWillConnectToServerAnonymously() { var client = new Mock <ISmtpClient>(); var bootstrapper = ConfigureServices(services => services.AddTransient(_ => client.Object)); var sut = bootstrapper.GetService <IMailSender>(); var account = new EmailConfig.OutgoingConfig { Username = "******", Password = string.Empty }; var message = new MailMessage { Subject = Guid.NewGuid().ToString("n"), HtmlBody = nameof(WhenBothUsernameAndPasswordProvidedThenItWillUseThemToAuthenticate), From = account.Username, To = { "random@domain" } }; await sut.SendAsync(account, message); client.Verify(x => x.AuthenticateAsync(It.Is <string>(u => u == account.Username), It.Is <string>(p => p == account.Password), It.IsAny <CancellationToken>()), Times.Never); }
private async Task ConnectAsync(ISmtpClient client, EmailConfig.OutgoingConfig cfg, CancellationToken cancellationToken) { _log.LogDebug("Connecting to mail server using {@Config}", cfg); var socketOptions = client.ConfigureSecurity(cfg.UseSecureMode); await Policy .Handle <SocketException>().Or <System.IO.IOException>().Or <SslHandshakeException>() .WaitAndRetryAsync(_retryConfig.Max, _ => _retryConfig.Delay, (exc, delay, attempt, _) => _log.LogError(exc, Message.ConnError, attempt, cfg, delay)) .ExecuteAsync(token => client.ConnectAsync(cfg.ServerAddress, cfg.Port, socketOptions, token), cancellationToken); if (!string.IsNullOrWhiteSpace(cfg.Username) && !string.IsNullOrWhiteSpace(cfg.Password)) { await Policy.Handle <SocketException>() .WaitAndRetryAsync(_retryConfig.Max, _ => _retryConfig.Delay, (exc, delay, attempt, _) => _log.LogError(exc, Message.AuthError, attempt, cfg, delay)) .ExecuteAsync(token => client.AuthenticateAsync(cfg.Username, cfg.Password, token), cancellationToken); } }