-
-
Notifications
You must be signed in to change notification settings - Fork 382
Description
I have a use case where I want to use the Thread-Index header to link messages together (Yes I know there is also the References field but that one is not always filled in my case). I tried decoded this header AQHbJet7Z+efu/5M5UWYnpinBaQePrKfAKzegAAO5bCAAAHygIAAD3LwgAG3uyCAAAECjYAXUgfggASoxyCAAAqegIADX0fwgAFtahCAAAThwIAAAMtwgAAAupCAAAEUEIAAImAggAAHlkCAAC0xcA== with some example code that I found on the internet.
try
{
Raw = threadIndex;
var bytes = Convert.FromBase64String(threadIndex);
// Thread index length should be 22 plus extra 5 bytes per reply
if (bytes.Length < 22 || (bytes.Length - 22) % 5 != 0)
return;
Id = new Guid(bytes.Skip(6).Take(16).ToArray());
var childBlockCount = (bytes.Length - 22) / 5;
if (childBlockCount == 0)
Date = DateTime.FromFileTimeUtc(bytes.Skip(1).Take(6).Select(b => (long)b).Aggregate((l1, l2) => (l1 << 8) + l2) << 16).ToLocalTime();
else
{
Date = DateTime.FromFileTimeUtc(bytes.Take(6).Select(b => (long)b).Aggregate((l1, l2) => (l1 << 8) + l2) << 16).ToLocalTime();
Dates = [Date];
for (var i = 0; i < childBlockCount; i++)
{
var childTicks = bytes.Skip(22 + i * 5).Take(4).Select(b => (long)b).Aggregate((l1, l2) => (l1 << 8) + l2) << 18;
childTicks &= ~((long)1 << 50);
Date = Date.AddTicks(childTicks);
if (i < childBlockCount - 1) Dates.Add(Date);
}
}
}
catch
{
// Ignore
}With some headers this works but most of the times I just get dated in the year 1830 or in 1601 so something is different.
I also tried following this documentation --> https://learn.microsoft.com/en-us/office/client-developer/outlook/mapi/tracking-conversations?redirectedfrom=MSDN ... but still no luck.
internal ThreadIndex(string threadIndex)
{
try
{
Raw = threadIndex;
// Decode base64 string to bytes
var bytes = Convert.FromBase64String(threadIndex);
// Validate minimum length (22 bytes for the header block)
if (bytes.Length < 22 || (bytes.Length - 22) % 5 != 0)
return;
// Parse the header block
if (bytes[0] != 1) // Reserved byte must be 1
return;
// Extract and compute the date from the FILETIME format in the header
var headerTicks = bytes.Skip(1).Take(5).Select(b => (long)b).Aggregate((l1, l2) => (l1 << 8) + l2) << 16;
Date = DateTime.FromFileTimeUtc(headerTicks).ToLocalTime();
// Extract GUID from the header block
Id = new Guid(bytes.Skip(6).Take(16).ToArray());
// Prepare the list of dates
Dates = new List<DateTime> { Date };
// Parse child blocks (if present)
var childBlockCount = (bytes.Length - 22) / 5;
for (var i = 0; i < childBlockCount; i++)
{
// Extract each child block (5 bytes)
var childBytes = bytes.Skip(22 + i * 5).Take(5).ToArray();
// Extract the first bit (time encoding strategy)
var strategyBit = (childBytes[0] & 0b10000000) != 0;
// Extract the 31 bits for time difference
var timeDiff = ((childBytes[0] & 0b01111111) << 24)
| (childBytes[1] << 16)
| (childBytes[2] << 8)
| childBytes[3];
if (strategyBit)
timeDiff <<= 23; // High-precision, shift low 23 bits
else
timeDiff <<= 18; // Low-precision, shift low 18 bits
// Mask out the 50th bit to handle the encoding properly
timeDiff &= ~((long)1 << 50);
// Compute the child date using the time difference
var childDate = Date.AddTicks(timeDiff);
Dates.Add(childDate);
}
}
catch
{
// Ignore exceptions for invalid input
}
}So I was wondering if you ever tried to do something like this with MimeKit?