在网站上解析和显示MIME多部分电子邮件

5
我有一封原始邮件(MIME多部分),想在网站上展示它(例如在iframe中,带有HTML部分和纯文本部分的选项卡等)。是否有CPAN模块或Template :: Toolkit插件可以帮助我实现这一目标?
目前看来,我需要使用Email :: MIME解析消息,然后遍历所有部分,并为所有不同的mime类型编写处理程序。
这是一个冒险,但我想知道是否已经有人完成了所有这些工作?如果我自己尝试编写处理程序,这将是一个漫长而容易出错的过程。
感谢任何帮助。

1
重复的问题 https://dev59.com/m03Sa4cB1Zd3GeqPxKw_ - daxim
谢谢daxim,我之前找的时候没有发现。看起来我还是得使用Email::MIME。 - aidan
3个回答

6
我几个月前刚刚处理了这个问题。 我为我所工作的产品添加了电子邮件功能,包括发送和接收。 第一部分是向用户发送提醒,但我们不想为我们的客户管理员管理反弹消息,因此我们决定拥有一个消息收件箱,管理员可以在没有我们的情况下查看反弹和回复,并且管理员可以调整电子邮件地址,如果需要的话。
因此,我们接受所有发送到我们监视的收件箱的电子邮件。 我们使用VERP将电子邮件与用户关联,并将整个电子邮件存储在数据库中。 然后,当管理员请求查看电子邮件时,我们必须解析电子邮件。
我的第一次尝试与早期答案非常相似。如果其中一个部分是html,则显示它。如果是文本,则显示它。否则,显示原始的、未经处理的电子邮件。但这在几封不是由sendmail生成的电子邮件中很快崩溃了。Outlook、Exchange和其他几个电子邮件系统不会这样做,它们使用多部分来发送电子邮件。经过大量挖掘和咒骂,我发现问题似乎没有被很好地记录下来。通过查看MHonArc并阅读RFC(RFC2045和RFC2046),我最终选择了下面的解决方案。我决定不使用MHonArc,因为我无法轻松地重用解析和显示功能。我不会说这是完美的,但它已经足够好,我们使用它。
首先,取得消息并使用Email::MIME进行解析。然后使用Email::MIME给出的parts()数组调用名为get_part的函数。
对于每个传递的部分,get_part解码内容类型,在哈希表中查找它,如果存在,则调用与该内容类型相关联的函数。如果解码器能够给我们一些东西,则将其放入结果数组中。
这个解码器数组是拼图的最后一块。基本上,它定义了我可以处理的内容类型:
- text/html - text/plain - message/delivery-status(实际上也是纯文本) - multipart/mixed - multipart/related - multipart/alternative 对于非多部分的节,我原样返回。对于混合、相关和替代,我只需在该 MIME 节点上调用 get_parts 并返回结果。因为替代很特殊,所以在调用 get_parts 后还有一些额外的代码。如果它有一个 HTML 部分,它将仅返回 html,或者如果它有一个文本部分,它将仅返回文本部分。如果两者都没有,它将不会返回任何有效内容。
使用有效内容类型的哈希表的优点是,我可以根据需要轻松添加更多部分的逻辑。并且在完成 get_parts 时,您应该拥有所有感兴趣的内容的数组。

还有一件事需要提到的是,作为其中的一部分,我们创建了一个单独的域来提供这些消息。管理员工作的主要域将拒绝提供该消息并将浏览器重定向到我们的用户内容域。第二个域仅提供用户内容。这是为了帮助浏览器将内容正确地隔离在我们的主域之外。请参阅同源策略(http://en.wikipedia.org/wiki/Same_origin_policy)。


4

对我来说,这似乎不是一项困难的工作:

关于IT技术的内容
use Email::MIME;
my $parsed = Email::MIME->new($message);
my @parts = $parsed->parts; # These will be Email::MIME objects, too.
print <<EOF;
<html><head><title>!</title></head><body>
EOF
for my $part (@parts) {    
    my $content_type = $parsed->content_type;
    if ($content_type eq "text/plain") {
         print "<pre>", $part->body (), "</pre>\n";
    }
    elsif ($content_type eq "text/html") {
        print $part->body ();
    }        
    # Handle some more cases here
}
print <<EOF;
</body></html>
EOF

4
你需要对其进行清洗处理。你不希望电子邮件将任意JS注入到你的网站中! - Quentin
2
更不用说在 text/plain 部分中编码实体了。 - cjm
对我来说,这似乎并不是一项艰巨的工作。实体很容易处理:s/([<>&])/"&#".ord($1).";"/ge,而通过 HTML::Scrubber 进行 HTML 消毒也很简单。 - user181548
这正是我计划要做的,但我担心的是“在此处理更多情况”的部分。我对 MIME 多部分和所有不同类型的了解还不够,以免出错。我想将附件显示为纸夹等等...但也许我过于谨慎了...感谢您的帮助。 - aidan
2
很棒的答案。代码中有几个小错误。应该是$content_type = $part->content_type(而不是parsed->content_type)。另外,使用正则表达式来匹配$content_type($content_type =~ m / text \ / plain /),而不是字符串比较,因为可能会有字符集。 - Somesh Rao

2

这可能正是我正在寻找的东西。我会进行调查...谢谢。 - aidan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接