/// <summary> /// Returns the client. /// </summary> /// <param name="client">The client.</param> /// <param name="traceProperties">The trace properties.</param> /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns> public async Task ReturnClient(IDSSmtpClient client, Dictionary <string, string> traceProperties) { if (traceProperties == null) { traceProperties = new Dictionary <string, string>(); } if (client == null) { throw new ArgumentNullException(nameof(client)); } traceProperties["Id"] = Guid.NewGuid().ToString(); await SemaphoreSlim.WaitAsync().ConfigureAwait(false); try { if (currentClientCount <= MaxClientCount) { ClientList.Enqueue(client); this.logger.TraceInformation("SmtpClient returned to pool.", traceProperties); } else { currentClientCount--; client.Dispose(); this.logger.TraceInformation($"SmtpClient disposed. Current count: {currentClientCount}", traceProperties); } } finally { _ = SemaphoreSlim.Release(); } }
/// <summary> /// Gets the client. /// </summary> /// <param name="traceProperties">The trace properties.</param> /// <returns> /// A <see cref="IDSSmtpClient" />. /// </returns> public async Task <IDSSmtpClient> GetClient(Dictionary <string, string> traceProperties) { if (traceProperties == null) { traceProperties = new Dictionary <string, string>(); } traceProperties["Id"] = Guid.NewGuid().ToString(); IDSSmtpClient client = await this.TryGetClient(traceProperties, false).ConfigureAwait(false); int numberOfTries = 1; while (client == null) { if (numberOfTries > 5) { this.logger.WriteCustomEvent("TryGetClient exceeded max number of tries, overriding client creation.", traceProperties); this.logger.WriteMetric("SmtpClientPool_OneTimeClientCreation", 1, traceProperties); client = await this.TryGetClient(traceProperties, true).ConfigureAwait(false); return(client); } else { this.logger.TraceInformation($"ClientPoolRequestFailure, number of tries: {numberOfTries}.", traceProperties); this.logger.WriteMetric("SmtpClientPool_ClientPoolRequestFailure", 1, traceProperties); await Task.Delay(1000 *numberOfTries).ConfigureAwait(false); client = await this.TryGetClient(traceProperties, false).ConfigureAwait(false); numberOfTries++; } } return(client); }
private async Task SendItemAsync(MimeMessage message, Dictionary <string, string> traceProps) { IDSSmtpClient client = null; string status = "Fail"; DateTimeOffset startTime; Stopwatch timer = new Stopwatch(); try { client = await this.clientPool.GetClient(traceProps).ConfigureAwait(false); startTime = DateTimeOffset.Now; timer.Start(); try { await client.SendAsync(message, traceProps).ConfigureAwait(false); } catch (ServiceNotConnectedException svcEx) { string description = $"SmtpClient not connected: {svcEx.Source}"; string eventMsg = "Closed connection, requesting new SmtpClient."; this.logger.WriteException(svcEx, traceProps); this.logger.TraceInformation(eventMsg, traceProps); client.Refresh(traceProps); await client.SendAsync(message, traceProps).ConfigureAwait(false); } catch (IOException ioex) { string description = $"No response from MX endpoint: {ioex.Source}"; string eventMsg = "Socket failure, requesting new SmtpClient."; traceProps["Error Description"] = description; this.logger.WriteException(ioex, traceProps); this.logger.TraceInformation(eventMsg, traceProps); client.Refresh(traceProps); await client.SendAsync(message, traceProps).ConfigureAwait(false); } catch (SmtpCommandException ex) { this.logger.WriteException(ex, traceProps); this.logger.TraceInformation($"SmtpCommandException with message {ex.Message} has been handled ", traceProps); client.Refresh(traceProps); await client.SendAsync(message, traceProps).ConfigureAwait(false); } catch (SocketException ex) { this.logger.WriteException(ex, traceProps); this.logger.TraceInformation($"SocketException with message {ex.Message} has been handled ", traceProps); client.Refresh(traceProps); await client.SendAsync(message, traceProps).ConfigureAwait(false); } timer.Stop(); status = "Success"; } catch (SmtpProtocolException ex) { this.logger.WriteException(ex, traceProps); throw; } catch (SmtpCommandException ex) { string msg = string.Empty; switch (ex.ErrorCode) { case SmtpErrorCode.RecipientNotAccepted: msg = $"Recipient not accepted: {ex.Mailbox?.Address}"; break; case SmtpErrorCode.SenderNotAccepted: msg = $"Sender not accepted: {ex.Mailbox?.Address}"; break; case SmtpErrorCode.MessageNotAccepted: msg = "Message not accepted."; break; } traceProps["ErrorMessage"] = msg; this.logger.WriteException(ex, traceProps); throw; } catch (Exception ex) { this.logger.WriteException(ex, traceProps); throw; } finally { if (client != null) { await this.clientPool.ReturnClient(client, traceProps).ConfigureAwait(false); } traceProps["Status"] = status; traceProps["EndPoint"] = this.clientPool.EndPoint; var metrics = new Dictionary <string, double> { { "Duration", timer.Elapsed.TotalMilliseconds }, }; this.logger.WriteCustomEvent("DirectSendMailService_SendMail", traceProps, metrics); this.logger.WriteMetric("DirectSendMailService_SendMailCount", 1, traceProps); } }
/// <summary> /// Creates the client. /// </summary> /// <param name="traceProperties">The trace properties.</param> /// <returns>A <see cref="IDSSmtpClient"/>.</returns> internal IDSSmtpClient CreateClient() { IDSSmtpClient emailClient = this.factory.CreateClient(this.config, this.logger); return(emailClient); }