public async Task Send(string data) { OnBeforeSend?.Invoke(data); var byteData = Encoding.UTF8.GetBytes(data); var bytesCount = byteData.Length; var currentByte = 0; while (currentByte <= bytesCount) { bool lastChunk = currentByte + _bufferSize > bytesCount; var count = lastChunk ? bytesCount - currentByte : _bufferSize; await _client.SendAsync( new ArraySegment <byte>(byteData, currentByte, count), WebSocketMessageType.Text, lastChunk, _tokenSource.Token); currentByte += _bufferSize; } OnAfterSend?.Invoke(data); }
/// <summary> /// This is the procedure taking care of sending the message (or saving to a file, respectively). /// </summary> /// <param name="smtpClient">The fully configures SmtpClient used to send the MimeMessate</param> /// <param name="mimeMsg">Mime message to send.</param> /// <param name="config"></param> /// <exception> /// If the SMTP transaction is the cause, SmtpFailedRecipientsException, SmtpFailedRecipientException or SmtpException can be expected. /// These exceptions throw after re-trying to send after failures (i.e. after MaxFailures * RetryDelayTime). /// </exception> /// <exception cref="SmtpCommandException"></exception> /// <exception cref="SmtpProtocolException"></exception> /// <exception cref="AuthenticationException"></exception> /// <exception cref="System.Net.Sockets.SocketException"></exception> internal void SendMimeMessage(SmtpClient smtpClient, MimeMessage mimeMsg, SmtpClientConfig config) { var startTime = DateTime.Now; Exception sendException; // the client can rely on the sequence of events: OnBeforeSend, OnSendFailure (if any), OnAfterSend OnBeforeSend?.Invoke(smtpClient, new MailSenderBeforeSendEventArgs(config, mimeMsg, startTime, null, _cancellationTokenSource.Token.IsCancellationRequested)); var failureCounter = 0; do { try { sendException = null; const string mailExt = ".eml"; switch (config.MessageOutput) { case MessageOutput.None: break; case MessageOutput.Directory: mimeMsg.WriteTo(System.IO.Path.Combine(config.MailOutputDirectory, Guid.NewGuid().ToString("N") + mailExt), _cancellationTokenSource.Token); break; #if NETFRAMEWORK case MessageOutput.PickupDirectoryFromIis: // for requirements of message format see: https://technet.microsoft.com/en-us/library/bb124230(v=exchg.150).aspx // and here http://www.vsysad.com/2014/01/iis-smtp-folders-and-domains-explained/ mimeMsg.WriteTo(System.IO.Path.Combine(config.MailOutputDirectory, Guid.NewGuid().ToString("N") + mailExt), _cancellationTokenSource.Token); break; #endif default: SendMimeMessageToSmtpServer(smtpClient, mimeMsg, config); break; // break switch } // when SendMimeMessageToSmtpServer throws less than _maxFailures exceptions, // and succeeds after an exception, we MUST break the while loop here (else: infinite) break; } catch (Exception ex) { sendException = ex; // exceptions which are thrown by SmtpClient: if (ex is SmtpCommandException || ex is SmtpProtocolException || ex is AuthenticationException || ex is System.Net.Sockets.SocketException || ex is System.IO.IOException) { failureCounter++; OnSendFailure?.Invoke(smtpClient, new MailSenderSendFailureEventArgs(sendException, failureCounter, config, mimeMsg)); Thread.Sleep(config.RetryDelayTime); // on first SMTP failure switch to the backup configuration, if one exists if (failureCounter == 1 && config.MaxFailures > 1) { var backupConfig = Config.SmtpClientConfig.FirstOrDefault(c => !c.Equals(config)); if (backupConfig == null) { continue; } backupConfig.MaxFailures = config.MaxFailures; // keep the logic within the current loop unchanged config = backupConfig; smtpClient.Disconnect(false); smtpClient = GetInitializedSmtpClientDelegate(config); } if (failureCounter == config.MaxFailures && smtpClient.IsConnected) { smtpClient.Disconnect(false); } } else { failureCounter = config.MaxFailures; OnSendFailure?.Invoke(smtpClient, new MailSenderSendFailureEventArgs(sendException, 1, config, mimeMsg)); } } } while (failureCounter < config.MaxFailures && failureCounter > 0); OnAfterSend?.Invoke(smtpClient, new MailSenderAfterSendEventArgs(config, mimeMsg, startTime, DateTime.Now, sendException, _cancellationTokenSource.Token.IsCancellationRequested)); // Dispose the streams of file attachments and inline file attachments MailMergeMessage.DisposeFileStreams(mimeMsg); if (sendException != null) { throw sendException; } }
/// <summary> /// This is the procedure taking care of sending the message (or saving to a file, respectively). /// </summary> /// <param name="smtpClient">The fully configures SmtpClient used to send the MimeMessate</param> /// <param name="mimeMsg">Mime message to send.</param> /// <param name="config"></param> /// <exception> /// If the SMTP transaction is the cause, SmtpFailedRecipientsException, SmtpFailedRecipientException or SmtpException can be expected. /// These exceptions throw after re-trying to send after failures (i.e. after MaxFailures * RetryDelayTime). /// </exception> /// <exception cref="SmtpCommandException"></exception> /// <exception cref="SmtpProtocolException"></exception> /// <exception cref="AuthenticationException"></exception> /// <exception cref="System.Net.Sockets.SocketException"></exception> private async Task SendMimeMessageAsync(SmtpClient smtpClient, MimeMessage mimeMsg, SmtpClientConfig config) { var startTime = DateTime.Now; Exception sendException; // the client can rely on the sequence of events: OnBeforeSend, OnSendFailure (if any), OnAfterSend OnBeforeSend?.Invoke(smtpClient, new MailSenderBeforeSendEventArgs(config, mimeMsg, startTime, null, _cancellationTokenSource.Token.IsCancellationRequested)); var failureCounter = 0; do { try { sendException = null; const string mailExt = ".eml"; switch (config.MessageOutput) { case MessageOutput.None: break; case MessageOutput.Directory: mimeMsg.WriteTo(System.IO.Path.Combine(config.MailOutputDirectory, Guid.NewGuid().ToString("N") + mailExt), _cancellationTokenSource.Token); break; #if NET40 || NET45 case MessageOutput.PickupDirectoryFromIis: // for requirements of message format see: https://technet.microsoft.com/en-us/library/bb124230(v=exchg.150).aspx // and here http://www.vsysad.com/2014/01/iis-smtp-folders-and-domains-explained/ mimeMsg.WriteTo(System.IO.Path.Combine(config.MailOutputDirectory, Guid.NewGuid().ToString("N") + mailExt), _cancellationTokenSource.Token); break; #endif default: await SendMimeMessageToSmtpServerAsync(smtpClient, mimeMsg, config).ConfigureAwait(false); break; // break switch } // when SendMimeMessageToSmtpServer throws less than _maxFailures exceptions, // and succeeds after an exception, we MUST break the while loop here (else: infinite) break; } catch (Exception ex) { // exceptions which are thrown by SmtpClient: if (ex is SmtpCommandException || ex is SmtpProtocolException || ex is AuthenticationException || ex is System.Net.Sockets.SocketException) { failureCounter++; sendException = ex; OnSendFailure?.Invoke(smtpClient, new MailSenderSendFailureEventArgs(sendException, failureCounter, config, mimeMsg)); #if NET40 await TaskEx.Delay(config.RetryDelayTime, _cancellationTokenSource.Token).ConfigureAwait(false); #else await Task.Delay(config.RetryDelayTime, _cancellationTokenSource.Token).ConfigureAwait(false); #endif // on first SMTP failure switch to the backup configuration, if one exists if (failureCounter == 1 && config.MaxFailures > 1) { var backupConfig = Config.SmtpClientConfig.FirstOrDefault(c => c != config); if (backupConfig == null) { continue; } backupConfig.MaxFailures = config.MaxFailures; // keep the logic within the current loop unchanged SetConfigForSmtpClient(smtpClient, backupConfig); config = backupConfig; } } else { failureCounter = config.MaxFailures; sendException = ex; OnSendFailure?.Invoke(smtpClient, new MailSenderSendFailureEventArgs(sendException, 1, config, mimeMsg)); } } } while (failureCounter < config.MaxFailures && failureCounter > 0); OnAfterSend?.Invoke(smtpClient, new MailSenderAfterSendEventArgs(config, mimeMsg, startTime, DateTime.Now, sendException, _cancellationTokenSource.Token.IsCancellationRequested)); // Do some clean-up with the message foreach (var mimeEntity in mimeMsg.Attachments) { var att = mimeEntity as MimePart; att?.ContentObject.Stream.Dispose(); } if (sendException != null) { throw sendException; } }
private void Send <T>(Action <T> action, T param) { OnBeforeSend?.Invoke(); action(param); OnAfterSend?.Invoke(); }