Example #1
0
        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;
            }
        }
Example #4
0
 private void Send <T>(Action <T> action, T param)
 {
     OnBeforeSend?.Invoke();
     action(param);
     OnAfterSend?.Invoke();
 }