using System; using System.IO; using System.Text; using Google.Apis.Gmail.v1.Data; using HtmlAgilityPack; using MimeKit; using MimeKit.IO; using MimeKit.IO.Filters; using MimeKit.Utils; namespace Wino.Core.Extensions { public static class MimeExtensions { /// /// Returns MimeKit.MimeMessage instance for this GMail Message's Raw content. /// /// GMail message. public static MimeMessage GetGmailMimeMessage(this Message message) { if (message == null || message.Raw == null) return null; // Gmail raw is not base64 but base64Safe. We need to remove this HTML things. var base64Encoded = message.Raw.Replace(",", "=").Replace("-", "+").Replace("_", "/"); byte[] bytes = Encoding.ASCII.GetBytes(base64Encoded); var stream = new MemoryStream(bytes); // This method will dispose outer stream. using (stream) { using var filtered = new FilteredStream(stream); filtered.Add(DecoderFilter.Create(ContentEncoding.Base64)); return MimeMessage.Load(filtered); } } /// /// Sets html body replacing base64 images with cid linked resources. /// Updates text body based on html. /// /// Body builder. /// Html content that can have embedded images. /// Body builder with set HtmlBody. public static BodyBuilder SetHtmlBody(this BodyBuilder bodyBuilder, string htmlContent) { if (string.IsNullOrEmpty(htmlContent)) return bodyBuilder; var doc = new HtmlDocument(); doc.LoadHtml(htmlContent); var imgNodes = doc.DocumentNode.SelectNodes("//img"); if (imgNodes != null) { foreach (var node in imgNodes) { var src = node.GetAttributeValue("src", string.Empty); if (string.IsNullOrEmpty(src)) continue; if (!src.StartsWith("data:image")) { continue; } var parts = src.Substring(11).Split([";base64,"], StringSplitOptions.None); string mimeType = parts[0]; string base64Content = parts[1]; var alt = node.GetAttributeValue("alt", $"Embedded_Image.{mimeType}"); // Convert the base64 content to binary data byte[] imageData = Convert.FromBase64String(base64Content); // Create a new linked resource as MimePart var image = new MimePart("image", mimeType) { ContentId = MimeUtils.GenerateMessageId(), Content = new MimeContent(new MemoryStream(imageData)), ContentDisposition = new ContentDisposition(ContentDisposition.Inline), ContentDescription = alt.Replace(" ", "_"), FileName = alt, ContentTransferEncoding = ContentEncoding.Base64 }; bodyBuilder.LinkedResources.Add(image); node.SetAttributeValue("src", $"cid:{image.ContentId}"); } } bodyBuilder.HtmlBody = doc.DocumentNode.InnerHtml; if (!string.IsNullOrEmpty(bodyBuilder.HtmlBody)) { bodyBuilder.TextBody = HtmlAgilityPackExtensions.GetPreviewText(bodyBuilder.HtmlBody); } return bodyBuilder; } } }