110 lines
3.5 KiB
C#
110 lines
3.5 KiB
C#
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;
|
|
using Wino.Services.Extensions;
|
|
|
|
namespace Wino.Core.Extensions;
|
|
|
|
public static class MimeExtensions
|
|
{
|
|
/// <summary>
|
|
/// Returns MimeKit.MimeMessage instance for this GMail Message's Raw content.
|
|
/// </summary>
|
|
/// <param name="message">GMail message.</param>
|
|
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);
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Sets html body replacing base64 images with cid linked resources.
|
|
/// Updates text body based on html.
|
|
/// </summary>
|
|
/// <param name="bodyBuilder">Body builder.</param>
|
|
/// <param name="htmlContent">Html content that can have embedded images.</param>
|
|
/// <returns>Body builder with set HtmlBody.</returns>
|
|
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;
|
|
}
|
|
}
|