/// <summary> /// Send a message to the Receivers. This is (partly) a blocking function. /// </summary> /// <param name="message"> /// If the given object is a byte array, it will not be serialized. Otherwise, the object will be serialized using a binary formatter. /// </param> public void Send(object message) { lock (_lock) try { if (!IsDisposed) { SetTcpSenders(); BeforeMessageSent?.Invoke(this, new MessageEventArgs() { Handle = Handle, Message = message, RemoteEndPoints = _tcpSenders.Values.ToArray() }); if (_tcpSenders.Count != 0) { if (Buffered) { if (message.GetHashCode() != _hashcode) { _bytes = SerializeMessage(message); _hashcode = message.GetHashCode(); } Parallel.ForEach(_tcpSenders, (kvp) => Send(kvp.Key, kvp.Value, _bytes)); } else { Parallel.ForEach(_tcpSenders, (kvp) => Send(kvp.Key, kvp.Value, SerializeMessage(message))); } } AfterMessageSent?.Invoke(this, new MessageEventArgs() { Handle = Handle, Message = message, RemoteEndPoints = _tcpSenders.Values.ToArray() }); } } catch (Exception ex) { if (!IsDisposed && OnSendFailed != null) { OnSendFailed(this, new ErrorEventArgs(ex)); } } }
/// <inheritdoc cref="IMailClient.SendAsync(IMessageBuilder, IDataRecord, IEnumerable{IMessageMutator}, CancellationToken)"/> protected virtual async Task <(MimeMessage?Message, bool Stop)> SendAsyncImpl(IMessageBuilder messageBuilder, IDataRecord record, IEnumerable <IMessageMutator> messageMutators, IFormatProvider formatProvider, int index, int count, CancellationToken cancellationToken) { IMessageBuilder message = messageBuilder.Clone(); FormatMessage(message, record, formatProvider); foreach (IMessageMutator mutator in messageMutators) { try { message = mutator.Mutate(message, record); } catch (Exception e) { MessageMutationErrorEventArgs errorArgs = new MessageMutationErrorEventArgs(message, mutator, e); MessageMutationError?.Invoke(this, errorArgs); if (errorArgs.Stop) { return(null, true); } else if (errorArgs.Skip) { MessageProcessed?.Invoke(this, new MessageProcessedEventArgs(message.ToMessage(), index, count, ProcessedType.Skipped)); return(null, false); } else if (errorArgs.SkipMutation) { continue; } throw; } } BeforeMessageSentEventArgs beforeArgs = new BeforeMessageSentEventArgs(message); BeforeMessageSent?.Invoke(this, beforeArgs); if (beforeArgs.Stop) { return(null, true); } else if (beforeArgs.Skip) { MessageProcessed?.Invoke(this, new MessageProcessedEventArgs(message.ToMessage(), index, count, ProcessedType.Skipped)); return(null, false); } MimeMessage result = message.ToMessage(); int attempt = 0; while (true) { try { ITransferProgress transferProgress = new TransferProgress((bytesTransferred, totalSize) => MessageTransferProgress?.Invoke(this, new MessageTransferProgressEventArgs(result, bytesTransferred, totalSize))); await Client.SendAsync(result, cancellationToken, progress : transferProgress).ConfigureAwait(false); MessageSent?.Invoke(this, new MessageSentEventArgs(result)); MessageProcessed?.Invoke(this, new MessageProcessedEventArgs(result, index, count, ProcessedType.Sent)); return(result, false); } catch (Exception e) { MessageTransferErrorEventArgs errorArgs = new MessageTransferErrorEventArgs(result, e, ++attempt); MessageTransferError?.Invoke(this, errorArgs); if (errorArgs.Stop) { return(null, true); } else if (errorArgs.Skip) { MessageProcessed?.Invoke(this, new MessageProcessedEventArgs(result, index, count, ProcessedType.Skipped)); return(null, false); } else if (errorArgs.Retry) { continue; } throw; } } }