- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我使用的是名为EAgetmail的库来检索指定电子邮件的正文,并且运行良好,但是现在使用的是Mailkit。 EAgetmail的问题是message.body等同于用户在电子邮件客户端中看到的正文,但是在mailkit中它返回了许多不同的数据。
这是相关代码:
using (var client = new ImapClient())
{
client.Connect(emailServer, 993, true);
client.AuthenticationMechanisms.Remove("XOAUTH2");
client.Authenticate(username, password);
var inbox = client.Inbox;
inbox.Open(FolderAccess.ReadOnly);
SearchQuery query;
if (checkBox.IsChecked == false)
{
query = SearchQuery.DeliveredBefore((DateTime)dateEnd).And(
SearchQuery.DeliveredAfter((DateTime)dateStart)).And(
SearchQuery.SubjectContains("Subject to find"));
}
else
{
query = SearchQuery.SubjectContains("Subject to find");
}
foreach (var uid in inbox.Search(query))
{
var message = inbox.GetMessage(uid);
formEmails.Add(message.TextBody);
messageDate.Add(message.Date.LocalDateTime);
}
client.Disconnect(true);
}
最佳答案
关于电子邮件的一个常见误解是,有一个定义明确的邮件正文,然后是附件列表。事实并非如此。现实情况是,MIME是内容的树形结构,非常类似于文件系统。
幸运的是,MIME确实为邮件客户端应如何解释MIME部分的树结构定义了一组通用规则。 Content-Disposition
标头用于向接收客户端提供提示,以提示哪些部分应显示为消息正文的一部分,哪些部分应解释为附件。Content-Disposition
标头通常具有以下两个值之一:inline
或attachment
。
这些值的含义应该很明显。如果该值为attachment
,则所述MIME部分的内容将被表示为与核心消息分开的文件附件。但是,如果值为inline
,则该MIME部分的内容应在邮件客户端的核心消息正文呈现中内联显示。如果Content-Disposition
标头不存在,则应将其视为inline
值。
从技术上讲,每个缺少Content-Disposition
标头或标记为inline
的部分都是核心消息主体的一部分。
但是,还有更多的东西。
现代MIME消息通常包含一个multipart/alternative
MIME容器,该容器通常包含发件人编写的文本的text/plain
和text/html
版本。与text/html
版本相比,text/plain
版本的格式通常与发件人在其所见即所得编辑器中看到的格式更接近。
以两种格式发送消息文本的原因是,并非所有邮件客户端都能够显示HTML。
接收方客户端应仅显示multipart/alternative
容器中包含的备用视图之一。由于按照发送人在其所见即所得编辑器中所看到的内容从最不忠实到最忠实的顺序列出了替代视图,因此接收方客户端应从末尾开始遍历替代视图列表,然后向后工作,直到找到一部分能够显示。
例:
multipart/alternative
text/plain
text/html
text/html
部分列在最后,因为它最忠实于发件人在编写消息时在其所见即所得编辑器中看到的内容。
multipart/related
MIME容器而不是简单的
text/html
部分,以便将图像和其他多媒体内容嵌入HTML。
multipart/alternative
text/plain
multipart/related
text/html
image/jpeg
video/mp4
image/png
multipart/related
容器,其中包含引用同级视频和图像的消息正文的HTML版本。
MimeVisitor
类,用于访问MIME树结构中的每个节点。例如,以下
MimeVisitor
子类可用于生成将由浏览器控件(例如
WebBrowser
)呈现的HTML:
/// <summary>
/// Visits a MimeMessage and generates HTML suitable to be rendered by a browser control.
/// </summary>
class HtmlPreviewVisitor : MimeVisitor
{
List<MultipartRelated> stack = new List<MultipartRelated> ();
List<MimeEntity> attachments = new List<MimeEntity> ();
readonly string tempDir;
string body;
/// <summary>
/// Creates a new HtmlPreviewVisitor.
/// </summary>
/// <param name="tempDirectory">A temporary directory used for storing image files.</param>
public HtmlPreviewVisitor (string tempDirectory)
{
tempDir = tempDirectory;
}
/// <summary>
/// The list of attachments that were in the MimeMessage.
/// </summary>
public IList<MimeEntity> Attachments {
get { return attachments; }
}
/// <summary>
/// The HTML string that can be set on the BrowserControl.
/// </summary>
public string HtmlBody {
get { return body ?? string.Empty; }
}
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 && body == null; 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;
}
// Save the image to our temp directory and return a "file://" url suitable for
// the browser control to load.
// Note: if you'd rather embed the image data into the HTML, you can construct a
// "data:" url instead.
string SaveImage (MimePart image, string url)
{
string fileName = url.Replace (':', '_').Replace ('\\', '_').Replace ('/', '_');
string path = Path.Combine (tempDir, fileName);
if (!File.Exists (path)) {
using (var output = File.Create (path))
image.ContentObject.DecodeTo (output);
}
return "file://" + path.Replace ('\\', '/');
}
// Replaces <img src=...> urls that refer to images embedded within the message with
// "file://" urls that the browser control will actually be able to load.
void HtmlTagCallback (HtmlTagContext ctx, HtmlWriter htmlWriter)
{
if (ctx.TagId == HtmlTagId.Image && !ctx.IsEndTag && stack.Count > 0) {
ctx.WriteTag (htmlWriter, false);
// replace the src attribute with a file:// URL
foreach (var attribute in ctx.Attributes) {
if (attribute.Id == HtmlAttributeId.Src) {
MimePart image;
string url;
if (!TryGetImage (attribute.Value, out image)) {
htmlWriter.WriteAttribute (attribute);
continue;
}
url = SaveImage (image, attribute.Value);
htmlWriter.WriteAttributeName (attribute.Name);
htmlWriter.WriteAttributeValue (url);
} else {
htmlWriter.WriteAttribute (attribute);
}
}
} else if (ctx.TagId == HtmlTagId.Body && !ctx.IsEndTag) {
ctx.WriteTag (htmlWriter, false);
// add and/or replace oncontextmenu="return false;"
foreach (var attribute in ctx.Attributes) {
if (attribute.Name.ToLowerInvariant () == "oncontextmenu")
continue;
htmlWriter.WriteAttribute (attribute);
}
htmlWriter.WriteAttribute ("oncontextmenu", "return false;");
} else {
// pass the tag through to the output
ctx.WriteTag (htmlWriter, true);
}
}
protected override void VisitTextPart (TextPart entity)
{
TextConverter converter;
if (body != null) {
// since we've already found the body, treat this as an attachment
attachments.Add (entity);
return;
}
if (entity.IsHtml) {
converter = new HtmlToHtml {
HtmlTagCallback = HtmlTagCallback
};
} else if (entity.IsFlowed) {
var flowed = new FlowedToHtml ();
string delsp;
if (entity.ContentType.Parameters.TryGetValue ("delsp", out delsp))
flowed.DeleteSpace = delsp.ToLowerInvariant () == "yes";
converter = flowed;
} else {
converter = new TextToHtml ();
}
body = converter.Convert (entity.Text);
}
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);
}
}
void Render (MimeMessage message)
{
var tmpDir = Path.Combine (Path.GetTempPath (), message.MessageId);
var visitor = new HtmlPreviewVisitor (tmpDir);
Directory.CreateDirectory (tmpDir);
message.Accept (visitor);
DisplayHtml (visitor.HtmlBody);
DisplayAttachments (visitor.Attachments);
}
TextBody
和
HtmlBody
属性(最简单的方法)
MimeMessage
包括两个属性,可以帮助您获取消息正文的
text/plain
或
text/html
版本。它们分别是
TextBody
和
HtmlBody
。
HtmlBody
属性,可能是HTML部分是
multipart/related
的子级,从而允许它引用图像和其他包含在该<< cc>实体。此属性实际上仅是一个便利属性,并不是您自己遍历MIME结构的真正替代,因此您可以正确解释相关内容。
关于c# - 如何使用MimeKit获取电子邮件的所见即所得主体,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34980154/
我需要您在以下方面提供帮助。近一个月来,我一直在阅读有关任务和异步的内容。 我想尝试在一个简单的 wep api 项目中实现我新获得的知识。我有以下方法,并且它们都按预期工作: public Htt
我的可执行 jar 中有一个模板文件 (.xls)。不需要在运行时我需要为这个文件创建 100 多个副本(稍后将唯一地附加)。用于获取 jar 文件中的资源 (template.xls)。我正在使用
我在查看网站的模型代码时对原型(prototype)有疑问。我知道这对 Javascript 中的继承很有用。 在这个例子中... define([], function () { "use
影响我性能的前三项操作是: 获取滚动条 获取偏移高度 Ext.getStyle 为了解释我的应用程序中发生了什么:我有一个网格,其中有一列在每个单元格中呈现网格。当我几乎对网格的内容做任何事情时,它运
我正在使用以下函数来获取 URL 参数。 function gup(name, url) { name = name.replace(/[\[]/, '\\\[').replace(/[\]]/,
我最近一直在使用 sysctl 来做很多事情,现在我使用 HW_MACHINE_ARCH 变量。我正在使用以下代码。请注意,当我尝试获取其他变量 HW_MACHINE 时,此代码可以完美运行。我还认为
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 关闭 9 年前。 要求提供代码的问题必须表现出对所解决问题的最低限度的理解。包括尝试过的解决方案、为什么
由于使用 main-bower-files 作为使用 Gulp 的编译任务的一部分,我无法使用 node_modules 中的 webpack 来require 模块code> dir 因为我会弄乱当
关闭。这个问题需要更多focused .它目前不接受答案。 想改进这个问题吗? 更新问题,使其只关注一个问题 editing this post . 关闭 5 年前。 Improve this qu
我使用 Gridlayout 在一行中放置 4 个元素。首先,我有一个 JPanel,一切正常。对于行数变大并且我必须能够向下滚动的情况,我对其进行了一些更改。现在我的 JPanel 上添加了一个 J
由于以下原因,我想将 VolumeId 的值保存在变量中: #!/usr/bin/env python import boto3 import json import argparse import
我正在将 MSAL 版本 1.x 更新为 MSAL-browser 的 Angular 。所以我正在尝试从版本 1.x 迁移到 2.X.I 能够成功替换代码并且工作正常。但是我遇到了 acquireT
我知道有很多关于此的问题,例如 Getting daily averages with pandas和 How get monthly mean in pandas using groupby但我遇到
This is the query string that I am receiving in URL. Output url: /demo/analysis/test?startDate=Sat+
我正在尝试使用 javascript 中的以下代码访问 Geoserver 层 var gkvrtWmsSource =new ol.source.ImageWMS({ u
API 需要一个包含授权代码的 header 。这就是我到目前为止所拥有的: var fullUrl = 'https://api.ecobee.com/1/thermostat?json=\{"s
如何获取文件中的最后一个字符,如果是某个字符,则删除它而不将整个文件加载到内存中? 这就是我目前所拥有的。 using (var fileStream = new FileStream("file.t
我是这个社区的新手,想出了我的第一个问题。 我正在使用 JSP,我成功地创建了 JSP-Sites,它正在使用jsp:setParameter 和 jsp:getParameter 具有单个字符串。
在回答 StoreStore reordering happens when compiling C++ for x86 @Peter Cordes 写过 For Acquire/Release se
我有一个函数,我们将其命名为 X1,它返回变量 Y。该函数在操作 .on("focusout", X1) 中使用。如何获取变量Y?执行.on后X1的结果? 最佳答案 您可以更改 Y 的范围以使其位于函
我是一名优秀的程序员,十分优秀!