使用 Email::MIME 和 multipart/mixed with subparts 解析电子邮件

Posted

技术标签:

【中文标题】使用 Email::MIME 和 multipart/mixed with subparts 解析电子邮件【英文标题】:Parsing email with Email::MIME and multipart/mixed with subparts 【发布时间】:2017-08-07 00:13:39 【问题描述】:

我是 perl 新手,一直在使用 Email::MIME 来弄清楚如何正确解析包含多部分的电子邮件。我刚刚发现了另一种我目前的努力无法正确解读的组合。

     Content-Type: multipart/mixed; boundary="===============1811908679642194059=="
 MIME-Version: 1.0

 This is an OpenPGP/MIME signed message (RFC 4880 and 3156)
 --===============1811908679642194059==
 Content-Type: multipart/signed; micalg=pgp-sha256;
  protocol="application/pgp-signature";
  boundary="lGJM242FL2E9Wh4auTNwQRWOeFI0Wj9mB"

 This is an OpenPGP/MIME signed message (RFC 4880 and 3156)
 --lGJM242FL2E9Wh4auTNwQRWOeFI0Wj9mB
 Content-Type: multipart/alternative;
  boundary="------------CC2F0C038668F58F6EDEA0D2"

 This is a multi-part message in MIME format.
 --------------CC2F0C038668F58F6EDEA0D2
 Content-Type: text/plain; charset=windows-1252
 Content-Transfer-Encoding: quoted-printable

 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D

text/plain 部分是我想要的部分,但是阅读“text”组件只会给我“This is a multi-part...”这一行,仅此而已。这是我为阅读具有类似子部分的其他电子邮件而开发的代码,但它不能正确解释这封邮件。

它看起来与作为 Email::MIME 一部分的“body”功能有关:

 This decodes and returns the body of the object as a byte string. For
 top-level objects in multi-part messages, this is highly likely to be
 something like "This is a multi-part message in MIME format."

在 Email::MIME 中使用什么函数可以正确读取此内容类型?

如何正确识别此电子邮件中的内容类型?是“multipart/mixed”还是“text/plain”还是“multipart/alternative”?

我什至想在这里使用 subparts 方法吗?

 my @mailData;
 my $msg = Email::MIME->new($buf);
 foreach my $part ( $msg->subparts ) 
    foreach my $sub_part ($part->subparts) 
         print $sub_part->content_type;
        if ($sub_part->content_type =~ m!text!) 
            @mailData = split( '\n', $sub_part->body);
         
    
 

上面的代码只在@mailData 数组中打印“This is a multi-part message...”。

【问题讨论】:

添加了代码,哎呀。谢谢。 由于没有人尝试过,我会试一试。看起来您只是在查看短信的第二级“部分”。也许使用 walk_parts 方法来浏览电子邮件的所有部分?您可以打印出每个内容的类型和正文,以查看您的内容可能在哪里。希望能给您更多关于您的电子邮件中发生的事情的线索。 我了解到的是,我的代码只显示(只能访问)文本/ascii 部分之一,而使用 walk_parts 能够访问所有部分。我仍然不完全确定这是正确的方法。 【参考方案1】:

过去几天我一直在使用 Email::MIME、MIME::Parser 和 MIME::Entity 来自动处理大量电子邮件。我发现编码同一封电子邮件的标准方法太少了,这比我想象的要困难得多。

这是处理电子邮件标题和正文的一种非常可靠的方法。非常感谢一路上提供帮助的所有人。

 #!/usr/bin/perl -w

 use strict;
 use MIME::Parser;
 use MIME::Entity;
 use Email::MIME;

 # Read the email from STDIN
 my $buf;
 while(<STDIN> )
         $buf .= $_;
 

 # This creates msg-NNNN-N.txt and signature-N.asc files
 # and I don't know why. Related to output_to_core?
 my $parser = MIME::Parser->new;
 $parser->extract_uuencode(1);
 $parser->extract_nested_messages(1);
 $parser->output_to_core(0);

 # For reading headers
 my $entity = $parser->parse_data($buf);

 # For reading the body (of an mbox)
 my $msg = Email::MIME->new($buf);

 # Use MIME::Entity to read various headers. 
 my $subject = $entity->head->get('Subject');
 my $from = $entity->head->get('From');
 my $AdvDate = $entity->head->get('Date');
 $AdvDate =~ s/\n//g; $subject =~ s/\n//g; $from =~ s/\n//g;

 print "Subject: $subject\n";
 print "From: $from\n";
 print "Date: $AdvDate\n";

 my @mailData;

  # walk through all the different attachments. Stop at the first one that matches and
  # read its contents into mailData. The first one typically appeared to be the primary one.
  $msg->walk_parts(sub 
      my ($part) = @_;
      #warn($part->content_type . ": " . $part->subparts);
      if (($part->content_type =~ /text\/plain; charset=\"?utf-8\"?/i) && !@mailData) 
         #print $part->body;
         @mailData = split( '\n', $part->body);
      
      elsif (($part->content_type =~ /text\/plain; charset=\"?us-ascii\"?/i) && !@mailData) 
         #print $part->body;
         @mailData = split( '\n', $part->body);
      
      elsif (($part->content_type =~ /text\/plain; charset=\"?windows-1252\"?/i) && !@mailData) 
         #print $part->body;
         @mailData = split( '\n', $part->body);
      
      elsif (($part->content_type =~ /text\/plain; charset=\"?iso-8859-1\"?/i) && !@mailData) 
         #print $part->body;
         @mailData = split( '\n', $part->body);
      
  );


 # manipulate the body of the message stored in mailData
 foreach my $line (@mailData) 
        print "$line\n";
 

【讨论】:

以上是关于使用 Email::MIME 和 multipart/mixed with subparts 解析电子邮件的主要内容,如果未能解决你的问题,请参考以下文章

使用 Email::MIME 和 multipart/mixed with subparts 解析电子邮件

如何使用Email :: Mime与sendmail

在 Python 中构建电子邮件时,我应该何时使用 email.message.Message 与 email.mime.text.MIMEText?

如何使用 Email::MIME 更改一个部分的正文?或者:body_set 对谁起作用?

无法使用 Perl 中的 Email::MIME 从 google 群组帐户发送电子邮件/抄送不接收电子邮件

Python遇到ModuleNotFoundError: No module named 'email.mime'; 'email' is not a package问