有人对我如何清理传入电子邮件的正文有任何建议吗?我想删除免责声明、图像以及可能存在的任何以前的电子邮件文本,这样我就只剩下正文内容了。我的猜测是不可能以任何可靠的方式实现,但是有人尝试过吗?是否有任何图书馆适合这种事情?
6 回答
在电子邮件中,有几个约定的标记表示您希望删除的内容。您可以使用正则表达式查找这些行。我怀疑你不能很好地“清理”你的电子邮件,但你可以寻找一些东西:
- 以“>”开头的行(大于空格)标记一个引号
- 带有“--”的行(两个连字符,然后是空格,然后是换行符)标志着签名的开始,请参阅Wikipedia 上的签名块
- 多部分消息,边界以--开头,除此之外,您需要进行一些搜索以将消息正文部分与不需要的部分(如 base64 图像)分开
至于实际的 C# 实现,我将其留给您或其他 SOers。
一些显而易见的事情要注意:
- 如果邮件不是纯文本,则邮件将是多部分的 mime。任何类型为“image/*”(image/jpeg 等)的部分都可能被删除。很可能任何类型不是“text/*”的部分都可以通过。
- HTML 消息可能有一部分类型为“multipart/alternative”(我认为),并且有两部分,一个“text/plain”和一个“text/html”。这两个部分应该差不多,所以您可以删除 HTML 部分。如果唯一存在的部分是 HTML 位,您可能需要进行 HTML 到纯文本的转换。
- 引用文本的通常格式是在文本前加一个“>”字符。您应该能够删除这些行,除非该行以“>From”开头,在这种情况下,“>”已被插入以防止邮件阅读器认为“From”是新邮件的开始。
- 签名应该以“-- \r\n”开头,尽管很有可能缺少尾随空格。
OSBF-Lua 版本 3 有一个邮件解析库,它将处理 MIME 并将消息拆分为其 MIME 部分等等。我目前有一堆 Lua 脚本,它们可以做一些事情,比如忽略大多数非文本附件,喜欢纯文本而不是 HTML,等等。(我还在尝试保留引用时将长行换成了 80 个字符。)
至于删除以前引用的邮件,上面的建议都很好(你必须订阅一些无礼的邮件列表)。
可靠地删除免责声明可能会很困难。我的第一个选择是简单地维护一个免责声明库,该库将被从每封邮件的末尾剥离;我会编写一个脚本来方便我添加到库中。对于更复杂的东西,我会尝试某种机器学习。
自 2007 年 2 月以来,我一直致力于垃圾邮件过滤,我了解到与电子邮件有关的任何事情都是一团糟。一个好的经验法则是,无论你想做什么都比你想象的要难得多:-(
鉴于您的问题“是否可以以编程方式'清理'电子邮件?”,我会回答“不,不可靠”。
你面临的危险并不是真正的技术危险,而是社会学危险。
很容易发现和过滤掉消息的某些方面——比如图像。同样,过滤掉签名和免责声明也是可能的(尽管更具挑战性)。
真正的问题是错误的代价。
如果您的过滤器恰好删除了消息的关键部分,会发生什么?您可以追溯它以找到丢失的部分,还是您的过滤具有破坏性?更糟糕的是,你会注意到这件作品丢失了吗?
几年前我看过一个经典的喜剧小品就说明了这一点。两个人一起在汽车上工作。一个在下面做工作,另一个坐在附近阅读服务手册的说明——很明显,两个人都不知道自己在做什么,但他们正在尽力而为。
手动的家伙,大声朗读:“取消油底壳中心的粗体......” [翻页]
工具人:“好的,出来了。”
手动的家伙:“……在任何情况下。”
如果您创建自己的应用程序,我会查看正则表达式,查找文本并替换它。为了使应用程序更好一点,我将创建一个名为 Email 的类,在该类中我有一个名为 RAW 的属性和一个名为 Stripped 的属性。
只是一些提示,当您查看正则表达式时,您将收集其余部分!
SigParser有一个可以在 .NET 中使用的程序集。它以 HTML 和文本形式为您提供了正文,而其余的东西被剥离了。如果您给它一个 HTML 电子邮件,它会在需要时将电子邮件转换为文本。
var parser = new SigParser.EmailParsing.EmailParser();
var result = await parser.GetCleanedBodyAsync(new SigParser.EmailParsing.Models.CleanedBodyInput {
FromEmailAddress = "john.smith@example.com",
FromName = "John Smith",
TextBody = @"Hi Mark,
This is my message.
Thanks
John Smith
888-333-4434"
});
// This would print "Hi Mark,\r\nThis is my message."
Console.WriteLine(result.CleanedBodyPlain);