From 5f9b51e4db34b96a32559bdc904f20d5340f936e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Burak=20Kaan=20K=C3=B6se?= Date: Sat, 1 Nov 2025 21:46:23 +0100 Subject: [PATCH] Some threading stuff. --- .../Extensions/OutlookIntegratorExtensions.cs | 8 ++++- .../Synchronizers/OutlookSynchronizer.cs | 4 ++- .../Collections/WinoMailCollection.cs | 13 ++++---- Wino.Services/MailService.cs | 33 ++++++++++++++++++- 4 files changed, 49 insertions(+), 9 deletions(-) diff --git a/Wino.Core/Extensions/OutlookIntegratorExtensions.cs b/Wino.Core/Extensions/OutlookIntegratorExtensions.cs index 1073e117..18f6e2f7 100644 --- a/Wino.Core/Extensions/OutlookIntegratorExtensions.cs +++ b/Wino.Core/Extensions/OutlookIntegratorExtensions.cs @@ -69,7 +69,7 @@ public static class OutlookIntegratorExtensions return mailCopy; } - public static Message AsOutlookMessage(this MimeMessage mime, bool includeInternetHeaders) + public static Message AsOutlookMessage(this MimeMessage mime, bool includeInternetHeaders, string conversationId = null) { var fromAddress = GetRecipients(mime.From).ElementAt(0); var toAddresses = GetRecipients(mime.To).ToList(); @@ -93,6 +93,12 @@ public static class OutlookIntegratorExtensions Attachments = [] }; + // Set ConversationId if provided to maintain threading + if (!string.IsNullOrEmpty(conversationId)) + { + message.ConversationId = conversationId; + } + // Headers are only included when creating the draft. // When sending, they are not included. Graph will throw an error. diff --git a/Wino.Core/Synchronizers/OutlookSynchronizer.cs b/Wino.Core/Synchronizers/OutlookSynchronizer.cs index 4391a2fd..a934663c 100644 --- a/Wino.Core/Synchronizers/OutlookSynchronizer.cs +++ b/Wino.Core/Synchronizers/OutlookSynchronizer.cs @@ -1231,7 +1231,9 @@ public class OutlookSynchronizer : WinoSynchronizer - { + + await ExecuteUIThread(() => + { existingItem.MailCopy = updatedItem; }); - + UpdateUniqueIdHashes(existingItem, true); } @@ -702,10 +702,10 @@ public class WinoMailCollection : ObservableRecipient, IRecipient(this); Messenger.Register(this); Messenger.Send(new SelectedItemsChangedMessage()); diff --git a/Wino.Services/MailService.cs b/Wino.Services/MailService.cs index 75744284..f01abc2a 100644 --- a/Wino.Services/MailService.cs +++ b/Wino.Services/MailService.cs @@ -936,12 +936,43 @@ public class MailService : BaseDatabaseService, IMailService } // Manage "ThreadId-ConversationId" + // CRITICAL: In-Reply-To and References headers are essential for threading + // They must reference the original message's Message-ID from the MIME headers if (!string.IsNullOrEmpty(referenceMessage.MessageId)) { message.InReplyTo = referenceMessage.MessageId; - message.References.AddRange(referenceMessage.References); + + // Add all previous References first + if (referenceMessage.References != null && referenceMessage.References.Count > 0) + { + message.References.AddRange(referenceMessage.References); + } + + // Then add the message we're replying to message.References.Add(referenceMessage.MessageId); } + else + { + // WARNING: Reference message has no Message-ID! + // This will break threading. Try to use the MessageId from MailCopy if available. + var referenceMailCopy = draftCreationOptions.ReferencedMessage.MailCopy; + if (referenceMailCopy != null && !string.IsNullOrEmpty(referenceMailCopy.MessageId)) + { + message.InReplyTo = referenceMailCopy.MessageId; + + if (!string.IsNullOrEmpty(referenceMailCopy.References)) + { + // Parse the References string and add them + var references = referenceMailCopy.References.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + foreach (var reference in references) + { + message.References.Add(reference.Trim()); + } + } + + message.References.Add(referenceMailCopy.MessageId); + } + } message.Headers.Add("Thread-Topic", referenceMessage.Subject); }