Example #1
0
        private QueueItem CreateQueueItem(Queue queue, Message msg)
        {
            var itm = new QueueItem(queue);

            itm.DisplayName = msg.Label;
            itm.Id          = msg.Id;
            itm.ArrivedTime = msg.ArrivedTime;
            //itm.Content = ReadMessageStream(msg.BodyStream);

            itm.Headers = new Dictionary <string, string>();
            if (msg.Extension.Length > 0)
            {
                var stream = new MemoryStream(msg.Extension);
                var transportMessageHeaders = TransportMessageHeaders.Create(stream.ToArray());
                //var o = headerSerializer.Deserialize(stream);

                var contentType       = transportMessageHeaders["Content-Type"];
                var originalMessageId = transportMessageHeaders["Original-Message-Id"];

                if (contentType != null)
                {
                    itm.Headers.Add("Content-Type", contentType);
                }

                if (originalMessageId != null)
                {
                    itm.Headers.Add("Original-Message-Id", originalMessageId);
                }
            }


            return(itm);
        }
		public void A_message_is_send_using_a_transport()
		{
			var headers = new TransportMessageHeaders();
			headers.Add("Content-Type", "application/vnd.masstransit+json");

			_bytes = headers.GetBytes();
		}
Example #3
0
        public void Should_return_an_empty_array_for_no_headers()
        {
            var headers = new TransportMessageHeaders();

            headers.Add("Content-Type", null);
            headers.GetBytes().Length.ShouldEqual(0);
        }
Example #4
0
        public void A_message_is_send_using_a_transport()
        {
            var headers = new TransportMessageHeaders();

            headers.Add("Content-Type", "application/vnd.masstransit+json");

            _bytes = headers.GetBytes();
        }
Example #5
0
        public void Send(ISendContext context)
        {
            using (var message = new Message())
            {
                if (!string.IsNullOrEmpty(context.MessageType))
                {
                    message.Label = context.MessageType.Length > 250 ? context.MessageType.Substring(0, 250) : context.MessageType;
                }

                message.Recoverable        = _address.IsRecoverable;
                message.UseDeadLetterQueue = true; // in case lack of permission message will be redirected to dead letter

                if (context.ExpirationTime.HasValue)
                {
                    DateTime value = context.ExpirationTime.Value;
                    message.TimeToBeReceived = value.Kind == DateTimeKind.Utc ? value - SystemUtil.UtcNow : value - SystemUtil.Now;
                }

                context.SerializeTo(message.BodyStream);

                var headers = new TransportMessageHeaders();

                if (!string.IsNullOrEmpty(context.ContentType))
                {
                    headers.Add("Content-Type", context.ContentType);
                }
                if (!string.IsNullOrEmpty(context.OriginalMessageId))
                {
                    headers.Add("Original-Message-Id", context.OriginalMessageId);
                }

                message.Extension = headers.GetBytes();

                try
                {
                    _connectionHandler.Use(connection => SendMessage(connection.Queue, message));

                    _address.LogSent(message.Id, context.MessageType);
                }
                catch (MessageQueueException ex)
                {
                    HandleOutboundMessageQueueException(ex);
                }
            }
        }
        public void Receive(Func <IReceiveContext, Action <IReceiveContext> > lookupSinkChain, TimeSpan timeout)
        {
            var handler = new TimeoutHandler(timeout);

            handler.Run((timedOut) => _connectionHandler.Use(connection =>
            {
                foreach (var message in connection.Queue.Messages)
                {
                    if (timedOut())
                    {
                        break;
                    }

                    using (var body = new MemoryStream(message.Body))
                    {
                        var context = ReceiveContext.FromBodyStream(body, Address.IsTransactional);

                        context.SetMessageId("{0}".FormatWith(message.Id));
                        context.SetInputAddress(Address);

                        byte[] extension = message.Extension;
                        if (extension.Length > 0)
                        {
                            var headers = TransportMessageHeaders.Create(extension);

                            context.SetContentType(headers["Content-Type"]);
                            context.SetOriginalMessageId(headers["Original-Message-Id"]);
                        }

                        Action <IReceiveContext> receive = lookupSinkChain(context);


                        if (receive != null)
                        {
                            if (!connection.Queue.TryRemoveMessage(message))
                            {
                                continue;
                            }

                            receive(context);
                        }
                    }
                }
            }));
        }
Example #7
0
        public void Send(ISendContext context)
        {
            using (var message = new Message())
            {
                if (!string.IsNullOrEmpty(context.MessageType))
                {
                    message.Label = context.MessageType.Length > 250 ? context.MessageType.Substring(0, 250) : context.MessageType;
                }

                message.Recoverable = true;

                if (context.ExpirationTime.HasValue)
                {
                    DateTime value = context.ExpirationTime.Value;
                    message.TimeToBeReceived = value.Kind == DateTimeKind.Utc ? value - SystemUtil.UtcNow : value - SystemUtil.Now;
                }

                context.SerializeTo(message.BodyStream);

                if (context.ContentType != null)
                {
                    var headers = new TransportMessageHeaders();
                    headers.Add("Content-Type", context.ContentType);

                    message.Extension = headers.GetBytes();
                }

                try
                {
                    _connectionHandler.Use(connection => SendMessage(connection.Queue, message));

                    if (_messageLog.IsDebugEnabled)
                    {
                        _messageLog.DebugFormat("SEND:{0}:{1}:{2}", _address.OutboundFormatName, message.Label, message.Id);
                    }
                }
                catch (MessageQueueException ex)
                {
                    HandleOutboundMessageQueueException(ex);
                }
            }
        }
        public void Send(ISendContext context)
        {
            using (var message = new Message())
            {
                if (!string.IsNullOrEmpty(context.MessageType))
                    message.Label = context.MessageType.Length > 250 ? context.MessageType.Substring(0, 250) : context.MessageType;

                message.Recoverable = _address.IsRecoverable;
                message.UseDeadLetterQueue = true; // in case lack of permission message will be redirected to dead letter

                if (context.ExpirationTime.HasValue)
                {
                    DateTime value = context.ExpirationTime.Value;
                    message.TimeToBeReceived = value.Kind == DateTimeKind.Utc ? value - SystemUtil.UtcNow : value - SystemUtil.Now;
                }

                context.SerializeTo(message.BodyStream);

                var headers = new TransportMessageHeaders();

                if (!string.IsNullOrEmpty(context.ContentType))
                    headers.Add("Content-Type", context.ContentType);
                if (!string.IsNullOrEmpty(context.OriginalMessageId))
                    headers.Add("Original-Message-Id", context.OriginalMessageId);
                
                message.Extension = headers.GetBytes();

                try
                {
                    _connectionHandler.Use(connection => SendMessage(connection.Queue, message));

                    _address.LogSent(message.Id, context.MessageType);

                }
                catch (MessageQueueException ex)
                {
                    HandleOutboundMessageQueueException(ex);
                }
            }
        }
		public void Send(ISendContext context)
		{
			using (var message = new Message())
			{
				if (!string.IsNullOrEmpty(context.MessageType))
					message.Label = context.MessageType.Length > 250 ? context.MessageType.Substring(0, 250) : context.MessageType;

				message.Recoverable = true;

				if (context.ExpirationTime.HasValue)
				{
					DateTime value = context.ExpirationTime.Value;
					message.TimeToBeReceived = value.Kind == DateTimeKind.Utc ? value - SystemUtil.UtcNow : value - SystemUtil.Now;
				}

				context.SerializeTo(message.BodyStream);

				if (context.ContentType != null)
				{
					var headers = new TransportMessageHeaders();
					headers.Add("Content-Type", context.ContentType);

					message.Extension = headers.GetBytes();
				}

				try
				{
					_connectionHandler.Use(connection => SendMessage(connection.Queue, message));

					if (_messageLog.IsDebugEnabled)
						_messageLog.DebugFormat("SEND:{0}:{1}:{2}", _address.OutboundFormatName, message.Label, message.Id);
				}
				catch (MessageQueueException ex)
				{
					HandleOutboundMessageQueueException(ex);
				}
			}
		}
        public void Send(ISendContext context)
        {
            _connectionHandler.Use(connection =>
            {
                var
                message = new SqlMessage {
                    Label = context.MessageType
                };

                if (context.ExpirationTime.HasValue)
                {
                    DateTime value           = context.ExpirationTime.Value;
                    message.TimeToBeReceived = value.Kind == DateTimeKind.Utc ? value - SystemUtil.UtcNow : value - SystemUtil.Now;
                }

                var bodyStream = new MemoryStream();

                context.SerializeTo(bodyStream);

                message.Body = bodyStream.ToArray();

                var headers = new TransportMessageHeaders();

                if (!string.IsNullOrEmpty(context.ContentType))
                {
                    headers.Add("Content-Type", context.ContentType);
                }
                if (!string.IsNullOrEmpty(context.OriginalMessageId))
                {
                    headers.Add("Original-Message-Id", context.OriginalMessageId);
                }

                message.Extension = headers.GetBytes();

                connection.Queue.Enqueue(message);
                Console.WriteLine("{3} Sendt message: Label {1} Size {2}".FormatWith(message.Id, message.Label, message.Body.Length, Address.Uri));
            });
        }
Example #11
0
        protected bool EnumerateQueue(Func <IReceiveContext, Action <IReceiveContext> > receiver, TimeSpan timeout)
        {
            if (_disposed)
            {
                throw new ObjectDisposedException("The transport has been disposed: '{0}'".FormatWith(Address));
            }

            bool received = false;

            _connectionHandler.Use(connection =>
            {
                using (MessageEnumerator enumerator = connection.Queue.GetMessageEnumerator2())
                {
                    // if (_log.IsDebugEnabled)
                    // _log.DebugFormat("Enumerating endpoint: {0} ({1}ms)", Address, timeout);

                    while (enumerator.MoveNext(timeout))
                    {
                        if (enumerator.Current == null)
                        {
                            if (_log.IsDebugEnabled)
                            {
                                _log.DebugFormat("Current message was null while enumerating endpoint");
                            }

                            continue;
                        }

                        Message peekMessage = enumerator.Current;
                        using (peekMessage)
                        {
                            IReceiveContext context = ReceiveContext.FromBodyStream(peekMessage.BodyStream);
                            context.SetMessageId(peekMessage.Id);
                            context.SetInputAddress(_address);

                            byte[] extension = peekMessage.Extension;
                            if (extension.Length > 0)
                            {
                                TransportMessageHeaders headers = TransportMessageHeaders.Create(extension);

                                context.SetContentType(headers["Content-Type"]);
                            }

                            Action <IReceiveContext> receive = receiver(context);
                            if (receive == null)
                            {
                                if (_log.IsDebugEnabled)
                                {
                                    _log.DebugFormat("SKIP:{0}:{1}", Address, peekMessage.Id);
                                }

                                continue;
                            }

                            ReceiveMessage(enumerator, timeout, message =>
                            {
                                if (message == null)
                                {
                                    throw new TransportException(Address.Uri,
                                                                 "Unable to remove message from queue: " + context.MessageId);
                                }

                                if (message.Id != context.MessageId)
                                {
                                    throw new TransportException(Address.Uri,
                                                                 string.Format(
                                                                     "Received message does not match current message: ({0} != {1})",
                                                                     message.Id, context.MessageId));
                                }

                                if (_messageLog.IsDebugEnabled)
                                {
                                    _messageLog.DebugFormat("RECV:{0}:{1}:{2}", _address.InboundFormatName,
                                                            message.Label, message.Id);
                                }

                                receive(context);

                                received = true;
                            });
                        }
                    }
                }
            });

            return(received);
        }
Example #12
0
        protected void EnumerateQueue(Func <IReceiveContext, Action <IReceiveContext> > receiver, TimeSpan timeout)
        {
            if (_disposed)
            {
                throw new ObjectDisposedException("The transport has been disposed: '{0}'".FormatWith(Address));
            }

            _connectionHandler.Use(connection =>
            {
                try
                {
                    using (MessageEnumerator enumerator = connection.Queue.GetMessageEnumerator2())
                    {
                        while (enumerator.MoveNext(timeout))
                        {
                            if (enumerator.Current == null)
                            {
                                if (_log.IsDebugEnabled)
                                {
                                    _log.DebugFormat("Current message was null while enumerating endpoint");
                                }

                                continue;
                            }

                            Message peekMessage = enumerator.Current;
                            using (peekMessage)
                            {
                                IReceiveContext context = ReceiveContext.FromBodyStream(peekMessage.BodyStream,
                                                                                        _address.IsTransactional);
                                context.SetMessageId(peekMessage.Id);
                                context.SetInputAddress(_address);

                                byte[] extension = peekMessage.Extension;
                                if (extension.Length > 0)
                                {
                                    TransportMessageHeaders headers = TransportMessageHeaders.Create(extension);

                                    context.SetContentType(headers["Content-Type"]);
                                    context.SetOriginalMessageId(headers["Original-Message-Id"]);
                                }

                                Action <IReceiveContext> receive = receiver(context);
                                if (receive == null)
                                {
                                    continue;
                                }

                                ReceiveMessage(enumerator, timeout, message =>
                                {
                                    if (message == null)
                                    {
                                        throw new TransportException(Address.Uri,
                                                                     "Unable to remove message from queue: " + context.MessageId);
                                    }

                                    if (message.Id != context.MessageId)
                                    {
                                        throw new TransportException(Address.Uri,
                                                                     string.Format(
                                                                         "Received message does not match current message: ({0} != {1})",
                                                                         message.Id, context.MessageId));
                                    }

                                    receive(context);
                                });
                            }
                        }
                    }
                }
                catch (MessageQueueException ex)
                {
                    HandleInboundMessageQueueException(ex);
                }
            });
        }
Example #13
0
        public static void QueueMessage <T>(T message) where T : class
        {
            string localQueueName = new Uri(QueueName).GetLocalName();

            ISendContext <T> sc = new SendContext <T>(message);
            var messageEnvelope = Envelope.Create(sc);

            messageEnvelope.DestinationAddress = QueueName;

            /* using (var mq = new System.Messaging.MessageQueue(localQueueName))
             * {
             *  mq.Send(messageEnvelope);
             *
             * }
             */

            var msmqMessage = new Message();

            try
            {
                if (!string.IsNullOrEmpty(sc.MessageType))
                {
                    msmqMessage.Label = sc.MessageType.Length > 250 ? sc.MessageType.Substring(0, 250) : sc.MessageType;
                }

                msmqMessage.Recoverable        = false;
                msmqMessage.UseDeadLetterQueue = true;

                if (sc.ExpirationTime.HasValue)
                {
                    DateTime dateTime = sc.ExpirationTime.Value;
                    msmqMessage.TimeToBeReceived = dateTime.Kind == DateTimeKind.Utc
                                                       ? dateTime - SystemUtil.UtcNow
                                                       : dateTime - SystemUtil.Now;
                }

                var serializer = new XmlMessageSerializer();

                // (Action<Stream>)(stream => serializer.Serialize<T>(stream, sc))

                sc.SetBodyWriter(stream => serializer.Serialize(stream, sc));
                sc.SerializeTo(msmqMessage.BodyStream);

                // msmqMessage.Body = messageEnvelope;

                var transportMessageHeaders = new TransportMessageHeaders();

                if (!string.IsNullOrEmpty(sc.ContentType))
                {
                    transportMessageHeaders.Add("Content-Type", sc.ContentType);
                }

                if (!string.IsNullOrEmpty(sc.OriginalMessageId))
                {
                    transportMessageHeaders.Add("Original-Message-Id", sc.OriginalMessageId);
                }

                msmqMessage.Extension = transportMessageHeaders.GetBytes();

                using (var mq = new MessageQueue(localQueueName))
                {
                    mq.Send(msmqMessage, MessageQueueTransactionType.None);
                }
            }
            finally
            {
                msmqMessage.Dispose();
            }
        }
		public void Should_return_an_empty_array_for_no_headers()
		{
			var headers = new TransportMessageHeaders();
			headers.Add("Content-Type", null);
			headers.GetBytes().Length.ShouldEqual(0);
		}
        /// <summary>
        /// May throw a timeout exception if a message with the given id cannot be found.
        /// </summary>
        /// <param name="messageId"></param>
        public void ReturnMessageToSourceQueue(string messageId, IReceiveContext context)
        {
            try
            {
                var query      = context.DestinationAddress.Query;
                var errorQueue = context.DestinationAddress.OriginalString.Replace(query, "") + "_error";

                Uri fromUri = new Uri(errorQueue);
                Uri toUri   = context.DestinationAddress;

                IInboundTransport  fromTransport = Transports.GetInboundTransport(fromUri);
                IOutboundTransport toTransport   = Transports.GetOutboundTransport(toUri);

                fromTransport.Receive(receiveContext =>
                {
                    if (receiveContext.MessageId == messageId)
                    {
                        return(ctx =>
                        {
                            var moveContext = new MoveMessageSendContext(ctx);
                            toTransport.Send(moveContext);
                        });
                    }

                    return(null);
                }, 5.Seconds());

                Console.WriteLine("Success.");
            }
            catch (MessageQueueException ex)
            {
                if (ex.MessageQueueErrorCode == MessageQueueErrorCode.IOTimeout)
                {
                    Console.WriteLine(NoMessageFoundErrorFormat, context.Id);

                    foreach (var m in queue.GetAllMessages())
                    {
                        var tm = TransportMessageHeaders.Create(m.Extension);

                        if (tm[""] != null)
                        {
                            //if (messageId != tm[""])
                            //    continue;

                            Console.WriteLine("Found message - going to return to queue.");

                            using (var tx = new TransactionScope())
                            {
                                using (var q = new MessageQueue(new EndpointAddress(tm[""]).Path))
                                    q.Send(m, MessageQueueTransactionType.Automatic);

                                queue.ReceiveByLookupId(MessageLookupAction.Current, m.LookupId,
                                                        MessageQueueTransactionType.Automatic);

                                tx.Complete();
                            }

                            Console.WriteLine("Success.");
                            //scope.Complete();

                            return;
                        }
                    }
                }
            }
            //}
        }
Example #16
0
        public void Should_reload_the_byte_array_into_a_headers_object()
        {
            var headers = TransportMessageHeaders.Create(_bytes);

            headers["Content-Type"].ShouldEqual("application/vnd.masstransit+json");
        }
Example #17
0
        /// <summary>
        ///     Writes all the properties that are part of the <see cref="Email"/> object either as <see cref="CFStorage"/>'s
        ///     or <see cref="CFStream"/>'s to the <see cref="CompoundFile.RootStorage"/>
        /// </summary>
        internal void WriteToStorage()
        {
            var rootStorage = CompoundFile.RootStorage;

            if (Class == MessageClass.Unknown)
            {
                Class = MessageClass.IPM_Note;
            }

            MessageSize += Recipients.WriteToStorage(rootStorage);
            MessageSize += Attachments.WriteToStorage(rootStorage);

            var recipientCount  = Recipients.Count;
            var attachmentCount = Attachments.Count;

            TopLevelProperties.RecipientCount   = recipientCount;
            TopLevelProperties.AttachmentCount  = attachmentCount;
            TopLevelProperties.NextRecipientId  = recipientCount;
            TopLevelProperties.NextAttachmentId = attachmentCount;

            TopLevelProperties.AddProperty(PropertyTags.PR_ENTRYID, Mapi.GenerateEntryId());
            TopLevelProperties.AddProperty(PropertyTags.PR_INSTANCE_KEY, Mapi.GenerateInstanceKey());
            TopLevelProperties.AddProperty(PropertyTags.PR_STORE_SUPPORT_MASK, StoreSupportMaskConst.StoreSupportMask, PropertyFlags.PROPATTR_READABLE);
            TopLevelProperties.AddProperty(PropertyTags.PR_STORE_UNICODE_MASK, StoreSupportMaskConst.StoreSupportMask, PropertyFlags.PROPATTR_READABLE);
            TopLevelProperties.AddProperty(PropertyTags.PR_ALTERNATE_RECIPIENT_ALLOWED, true, PropertyFlags.PROPATTR_READABLE);
            TopLevelProperties.AddProperty(PropertyTags.PR_HASATTACH, attachmentCount > 0);

            if (TransportMessageHeaders != null)
            {
                TopLevelProperties.AddProperty(PropertyTags.PR_TRANSPORT_MESSAGE_HEADERS_W, TransportMessageHeaders.ToString());

                if (!string.IsNullOrWhiteSpace(TransportMessageHeaders.MessageId))
                {
                    TopLevelProperties.AddProperty(PropertyTags.PR_INTERNET_MESSAGE_ID_W, TransportMessageHeaders.MessageId);
                }

                if (TransportMessageHeaders.References.Any())
                {
                    TopLevelProperties.AddProperty(PropertyTags.PR_INTERNET_REFERENCES_W, TransportMessageHeaders.References.Last());
                }

                if (TransportMessageHeaders.InReplyTo.Any())
                {
                    TopLevelProperties.AddProperty(PropertyTags.PR_IN_REPLY_TO_ID_W, TransportMessageHeaders.InReplyTo.Last());
                }
            }

            if (!string.IsNullOrWhiteSpace(InternetMessageId))
            {
                TopLevelProperties.AddOrReplaceProperty(PropertyTags.PR_INTERNET_MESSAGE_ID_W, InternetMessageId);
            }

            if (!string.IsNullOrWhiteSpace(InternetReferences))
            {
                TopLevelProperties.AddOrReplaceProperty(PropertyTags.PR_INTERNET_REFERENCES_W, InternetReferences);
            }

            if (!string.IsNullOrWhiteSpace(InReplyToId))
            {
                TopLevelProperties.AddOrReplaceProperty(PropertyTags.PR_IN_REPLY_TO_ID_W, InReplyToId);
            }

            var messageFlags = MessageFlags.MSGFLAG_UNMODIFIED;

            if (attachmentCount > 0)
            {
                messageFlags |= MessageFlags.MSGFLAG_HASATTACH;
            }

            TopLevelProperties.AddProperty(PropertyTags.PR_INTERNET_CPID, Encoding.UTF8.CodePage);

            TopLevelProperties.AddProperty(PropertyTags.PR_BODY_W, BodyText);

            if (!string.IsNullOrEmpty(BodyHtml) && !Draft)
            {
                TopLevelProperties.AddProperty(PropertyTags.PR_HTML, BodyHtml);
                TopLevelProperties.AddProperty(PropertyTags.PR_RTF_IN_SYNC, false);
            }
            else if (string.IsNullOrWhiteSpace(BodyRtf) && !string.IsNullOrWhiteSpace(BodyHtml))
            {
                BodyRtf           = Strings.GetEscapedRtf(BodyHtml);
                BodyRtfCompressed = true;
            }

            if (!string.IsNullOrWhiteSpace(BodyRtf))
            {
                TopLevelProperties.AddProperty(PropertyTags.PR_RTF_COMPRESSED, new RtfCompressor().Compress(Encoding.ASCII.GetBytes(BodyRtf)));
                TopLevelProperties.AddProperty(PropertyTags.PR_RTF_IN_SYNC, BodyRtfCompressed);
            }

            if (MessageEditorFormat != MessageEditorFormat.EDITOR_FORMAT_DONTKNOW)
            {
                TopLevelProperties.AddProperty(PropertyTags.PR_MSG_EDITOR_FORMAT, MessageEditorFormat);
            }

            if (!SentOn.HasValue)
            {
                SentOn = DateTime.UtcNow;
            }

            if (ReceivedOn.HasValue)
            {
                TopLevelProperties.AddProperty(PropertyTags.PR_MESSAGE_DELIVERY_TIME, ReceivedOn.Value.ToUniversalTime());
            }

            TopLevelProperties.AddProperty(PropertyTags.PR_CLIENT_SUBMIT_TIME, SentOn.Value.ToUniversalTime());
            TopLevelProperties.AddProperty(PropertyTags.PR_ACCESS, MapiAccess.MAPI_ACCESS_DELETE | MapiAccess.MAPI_ACCESS_MODIFY | MapiAccess.MAPI_ACCESS_READ);
            TopLevelProperties.AddProperty(PropertyTags.PR_ACCESS_LEVEL, MapiAccess.MAPI_ACCESS_MODIFY);
            TopLevelProperties.AddProperty(PropertyTags.PR_OBJECT_TYPE, MapiObjectType.MAPI_MESSAGE);

            SetSubject();
            TopLevelProperties.AddProperty(PropertyTags.PR_SUBJECT_W, Subject);
            TopLevelProperties.AddProperty(PropertyTags.PR_NORMALIZED_SUBJECT_W, SubjectNormalized);
            TopLevelProperties.AddProperty(PropertyTags.PR_SUBJECT_PREFIX_W, SubjectPrefix);
            TopLevelProperties.AddProperty(PropertyTags.PR_CONVERSATION_TOPIC_W, SubjectNormalized);

            // http://www.meridiandiscovery.com/how-to/e-mail-conversation-index-metadata-computer-forensics/
            // http://stackoverflow.com/questions/11860540/does-outlook-embed-a-messageid-or-equivalent-in-its-email-elements
            //propertiesStream.AddProperty(PropertyTags.PR_CONVERSATION_INDEX, Subject);

            // TODO: Change modification time when this message is opened and only modified
            var utcNow = DateTime.UtcNow;

            TopLevelProperties.AddProperty(PropertyTags.PR_CREATION_TIME, utcNow);
            TopLevelProperties.AddProperty(PropertyTags.PR_LAST_MODIFICATION_TIME, utcNow);
            TopLevelProperties.AddProperty(PropertyTags.PR_PRIORITY, Priority);
            TopLevelProperties.AddProperty(PropertyTags.PR_IMPORTANCE, Importance);
            TopLevelProperties.AddProperty(PropertyTags.PR_MESSAGE_LOCALE_ID, CultureInfo.CurrentCulture.LCID);

            if (Draft)
            {
                messageFlags |= MessageFlags.MSGFLAG_UNSENT;
                IconIndex     = MessageIconIndex.UnsentMail;
            }

            if (ReadRecipient)
            {
                TopLevelProperties.AddProperty(PropertyTags.PR_READ_RECEIPT_REQUESTED, true);
                var reportTag = new ReportTag {
                    ANSIText = Subject
                };
                TopLevelProperties.AddProperty(PropertyTags.PR_REPORT_TAG, reportTag.ToByteArray());
            }

            TopLevelProperties.AddProperty(PropertyTags.PR_MESSAGE_FLAGS, messageFlags);
            TopLevelProperties.AddProperty(PropertyTags.PR_ICON_INDEX, IconIndex);

            Sender?.WriteProperties(TopLevelProperties);
            Receiving?.WriteProperties(TopLevelProperties);
            Representing?.WriteProperties(TopLevelProperties);
            ReceivingRepresenting?.WriteProperties(TopLevelProperties);

            if (recipientCount > 0)
            {
                var displayTo  = new List <string>();
                var displayCc  = new List <string>();
                var displayBcc = new List <string>();

                foreach (var recipient in Recipients)
                {
                    switch (recipient.RecipientType)
                    {
                    case RecipientType.To:
                        if (!string.IsNullOrWhiteSpace(recipient.DisplayName))
                        {
                            displayTo.Add(recipient.DisplayName);
                        }
                        else if (!string.IsNullOrWhiteSpace(recipient.Email))
                        {
                            displayTo.Add(recipient.Email);
                        }
                        break;

                    case RecipientType.Cc:
                        if (!string.IsNullOrWhiteSpace(recipient.DisplayName))
                        {
                            displayCc.Add(recipient.DisplayName);
                        }
                        else if (!string.IsNullOrWhiteSpace(recipient.Email))
                        {
                            displayCc.Add(recipient.Email);
                        }
                        break;

                    case RecipientType.Bcc:
                        if (!string.IsNullOrWhiteSpace(recipient.DisplayName))
                        {
                            displayBcc.Add(recipient.DisplayName);
                        }
                        else if (!string.IsNullOrWhiteSpace(recipient.Email))
                        {
                            displayBcc.Add(recipient.Email);
                        }
                        break;

                    default:
                        throw new ArgumentOutOfRangeException();
                    }
                }

                TopLevelProperties.AddProperty(PropertyTags.PR_DISPLAY_TO_W, string.Join(";", displayTo), PropertyFlags.PROPATTR_READABLE);
                TopLevelProperties.AddProperty(PropertyTags.PR_DISPLAY_CC_W, string.Join(";", displayCc), PropertyFlags.PROPATTR_READABLE);
                TopLevelProperties.AddProperty(PropertyTags.PR_DISPLAY_BCC_W, string.Join(";", displayBcc), PropertyFlags.PROPATTR_READABLE);
            }
        }