我首先提到这个没有答案的问题,这与我的问题非常相似:
使用 openpop.pop3 区分电子邮件中的内联图像和签名图像
我没有足够的代表来评论这个问题,所以我制作了一个新的来引用它。
我需要一种方法来检查 openpop 中的附件,看看它是来自签名(通常是小徽标等)还是来自嵌入在电子邮件正文中的大图像。当您在许多邮件应用程序中添加图片作为附件时,智能手机通常会执行此操作。
我首先提到这个没有答案的问题,这与我的问题非常相似:
使用 openpop.pop3 区分电子邮件中的内联图像和签名图像
我没有足够的代表来评论这个问题,所以我制作了一个新的来引用它。
我需要一种方法来检查 openpop 中的附件,看看它是来自签名(通常是小徽标等)还是来自嵌入在电子邮件正文中的大图像。当您在许多邮件应用程序中添加图片作为附件时,智能手机通常会执行此操作。
您不能使用 OpenPOP.NET 轻松做到这一点,但使用 MailKit 做到这一点相当简单。
您可以从常见问题解答HtmlPreviewVisitor
中的示例开始,稍微修改一下,将附件分成 2 个列表:
代码:
/// <summary>
/// Visits a MimeMessage and splits attachments into those that are
/// referenced by the HTML body vs regular attachments.
/// </summary>
class AttachmentVisitor : MimeVisitor
{
List<MultipartRelated> stack = new List<MultipartRelated> ();
List<MimeEntity> attachments = new List<MimeEntity> ();
List<MimePart> embedded = new List<MimePart> ();
bool foundBody;
/// <summary>
/// Creates a new AttachmentVisitor.
/// </summary>
public AttachmentVisitor ()
{
}
/// <summary>
/// The list of attachments that were in the MimeMessage.
/// </summary>
public IList<MimeEntity> Attachments {
get { return attachments; }
}
/// <summary>
/// The list of embedded images that were in the MimeMessage.
/// </summary>
public IList<MimePart> EmbeddedImages {
get { return embedded; }
}
protected override void VisitMultipartAlternative (MultipartAlternative alternative)
{
// walk the multipart/alternative children backwards from greatest level of faithfulness to the least faithful
for (int i = alternative.Count - 1; i >= 0 && !foundBody; i--)
alternative[i].Accept (this);
}
protected override void VisitMultipartRelated (MultipartRelated related)
{
var root = related.Root;
// push this multipart/related onto our stack
stack.Add (related);
// visit the root document
root.Accept (this);
// pop this multipart/related off our stack
stack.RemoveAt (stack.Count - 1);
}
// look up the image based on the img src url within our multipart/related stack
bool TryGetImage (string url, out MimePart image)
{
UriKind kind;
int index;
Uri uri;
if (Uri.IsWellFormedUriString (url, UriKind.Absolute))
kind = UriKind.Absolute;
else if (Uri.IsWellFormedUriString (url, UriKind.Relative))
kind = UriKind.Relative;
else
kind = UriKind.RelativeOrAbsolute;
try {
uri = new Uri (url, kind);
} catch {
image = null;
return false;
}
for (int i = stack.Count - 1; i >= 0; i--) {
if ((index = stack[i].IndexOf (uri)) == -1)
continue;
image = stack[i][index] as MimePart;
return image != null;
}
image = null;
return false;
}
// called when an HTML tag is encountered
void HtmlTagCallback (HtmlTagContext ctx, HtmlWriter htmlWriter)
{
if (ctx.TagId == HtmlTagId.Image && !ctx.IsEndTag && stack.Count > 0) {
// search for the src= attribute
foreach (var attribute in ctx.Attributes) {
if (attribute.Id == HtmlAttributeId.Src) {
MimePart image;
if (!TryGetImage (attribute.Value, out image))
continue;
if (!embedded.Contains (image))
embedded.Add (image);
}
}
}
}
protected override void VisitTextPart (TextPart entity)
{
TextConverter converter;
if (foundBody) {
// since we've already found the body, treat this as an
// attachment
attachments.Add (entity);
return;
}
if (entity.IsHtml) {
converter = new HtmlToHtml {
HtmlTagCallback = HtmlTagCallback
};
converter.Convert (entity.Text);
}
foundBody = true;
}
protected override void VisitTnefPart (TnefPart entity)
{
// extract any attachments in the MS-TNEF part
attachments.AddRange (entity.ExtractAttachments ());
}
protected override void VisitMessagePart (MessagePart entity)
{
// treat message/rfc822 parts as attachments
attachments.Add (entity);
}
protected override void VisitMimePart (MimePart entity)
{
// realistically, if we've gotten this far, then we can treat
// this as an attachment even if the IsAttachment property is
// false.
attachments.Add (entity);
}
}
要使用它:
var visitor = new AttachmentVisitor ();
message.Accept (visitor);
// Now you can use visitor.Attachments and visitor.EmbeddedImages
一种更简单但防错性较差的方法是:
var signatureImages = message.BodyParts.OfType<MimePart> ().
Where (x => x.ContentType.IsMimeType ("image", "*") &&
x.ContentDisposition != null &&
x.ContentDisposition.Disposition.Equals ("inline" StringComparison.OrdinalIgnoreCase));