using System; using System.Collections.Generic; using System.Linq; namespace Wino.Core.Domain.Extensions; public static class MailHeaderExtensions { public static string NormalizeMessageId(string value) { if (value == null) return null; var normalized = StripAngleBrackets(value)?.Trim(); return string.IsNullOrWhiteSpace(normalized) ? string.Empty : normalized; } public static string ToHeaderMessageId(string value) { var normalized = NormalizeMessageId(value); return string.IsNullOrEmpty(normalized) ? string.Empty : $"<{normalized}>"; } /// /// Strips angle brackets from a Message-ID or In-Reply-To value. /// RFC 5322 Message-IDs are formatted as <id@domain>, but MimeKit /// properties store them without brackets. This normalizes raw header /// values to match MimeKit's convention. /// public static string StripAngleBrackets(string value) { if (string.IsNullOrEmpty(value)) return value; value = value.Trim(); if (value.StartsWith("<") && value.EndsWith(">")) return value.Substring(1, value.Length - 2); return value; } /// /// Normalizes a raw RFC References header value into semicolon-separated Message-IDs /// without angle brackets. Raw References headers contain space-separated bracketed IDs /// like "<id1@domain> <id2@domain>". This converts them to "id1@domain;id2@domain". /// public static string NormalizeReferences(string rawReferences) => JoinStoredReferences(SplitMessageIds(rawReferences)); public static IEnumerable SplitMessageIds(string values) { if (string.IsNullOrWhiteSpace(values)) return []; return values .Split(new[] { ' ', '\t', '\r', '\n', ';', ',' }, StringSplitOptions.RemoveEmptyEntries) .Select(NormalizeMessageId) .Where(id => !string.IsNullOrEmpty(id)); } public static string JoinStoredReferences(IEnumerable values) => string.Join(";", NormalizeDistinctMessageIds(values)); public static string BuildReferencesHeaderValue(IEnumerable values) => string.Join(" ", NormalizeDistinctMessageIds(values).Select(ToHeaderMessageId)); public static List BuildReferencesChain(IEnumerable existingReferences, string parentMessageId) { var results = NormalizeDistinctMessageIds(existingReferences).ToList(); var normalizedParentMessageId = NormalizeMessageId(parentMessageId); if (!string.IsNullOrEmpty(normalizedParentMessageId) && !results.Contains(normalizedParentMessageId, StringComparer.OrdinalIgnoreCase)) { results.Add(normalizedParentMessageId); } return results; } private static IEnumerable NormalizeDistinctMessageIds(IEnumerable values) { if (values == null) yield break; var seen = new HashSet(StringComparer.OrdinalIgnoreCase); foreach (var value in values) { var normalized = NormalizeMessageId(value); if (string.IsNullOrEmpty(normalized) || !seen.Add(normalized)) continue; yield return normalized; } } }