【问题标题】:Net::IMAP::Simple get not getting the entire messageNet::IMAP::Simple 没有得到整个消息
【发布时间】:2017-01-17 10:57:35
【问题描述】:

我对 perl 很陌生,所以也许我做了一些愚蠢的事情。 我的问题是我目前正在使用脚本通过 IMAP 协议获取电子邮件箱中包含的所有消息,在 PERL 中使用 Net::IMAP::Simple,但它没有给我整个消息正文。 我的整个代码如下所示:

      use strict;
      use Net::IMAP::Simple;
      
       my $imap = Net::IMAP::Simple->new('xxxxxxxxxxxxxx') or die 'Impossible to connect '.$!;
      $imap->login('xxxxxxxx', 'xxxxxxxxx') or die 'Login Error!';
      my $nbmsg = $imap->select('INBOX') or die 'Impossible to reach this folder !';
      print 'You have '.$nbmsg." messages in this folder !\n\n";
      my $index = $imap->list() or die 'Impossible to list these messages !';

    foreach my $msgnum (keys %$index) {
    #if(!$imap->seen($msgnum)) {
          my $msg = $imap->get($msgnum) or die 'Impossible to retrieve this message'.$msgnum.' !';
          print $msg."\n\n";
    #   }
    }
    $imap->quit() or die 'quitting issue !';

每次检索电子邮件时,它都会给我第一个字符(在我的情况下,这是发送消息的机器人生成的神秘无用元数据),而不是整个正文。

编辑:这是输出中显示的正文部分:

内容类型:文本/纯文本;字符集="utf-8" 内容传输编码:BASE64

Q2UgbWVzc2FnZSBhIMOpdMOpIGfDqW7DqXLDqSBhdXRvbWF0aXF1ZW1lbnQgcGFyIGwnaW1wcmlt YW50ZSBtdWx0aWZvbmN0aW9ucyBYZXJveCBYRVJPWF83ODMwLgogICBFbXBsYWNlbWVudCBkdSBz eXN0w6htZSA6IAogICBBZHJlc3NlIElQIHN5c3TDqG1lIDogMTkyLjE2OC4xLjIwMAogICBBZHJl c3NlIE1BQyBzeXN0w6htZSA6IDlDOjkzOjRFOjMzOjM1OkJECiAgIE1vZMOobGUgc3lzdMOobWUg OiBYZXJveCBXb3JrQ2VudHJlIDc4MzAKICAgTnVtw6lybyBkZSBzw6lyaWUgc3lzdMOobWUgOiAz OTEyNzk4ODk0CgpMJ0Fzc2lzdGFudCBkZSBjb21wdGV1ciBhIGVudm95w6kgbGUgcmVsZXbDqSBz dWl2YW50IGF1IHNlcnZldXIgZGUgY29tbXVuaWNhdGlvbiBYZXJveCBTTWFydCBlU29sdXRpb25z IGxlICAxNC8xMS8xNiAgIDA5OjI0OiAKICBUaXJhZ2VzIGVuIG5vaXIgOiAxMzIwNwogIFRpcmFn ZXMgZW4gY291bGV1ciA6IDkyNjg3CiAgVG91cyBsZXMgdGlyYWdlcyA6IDEwNTg5NA==

它总是以这个“==”结尾,这让我觉得模块正在缩短输出。

我在 CPAN 文档中查看了一些关于它的细节,但遗憾的是没有找到任何东西。

【问题讨论】:

  • edit 并包含该输出。我相信它实际上不是消息的一部分,而是$imap->get 返回的消息对象的ref。这些对象确实具有将它们转换为文本的字符串重载,但您没有使用它。您必须执行 print "$msg" 才能将其强制转换为字符串。
  • 我已经做到了。但这并没有改变什么。我正在编辑以添加输出。
  • 查看文档我认为您不需要获取list(),您也可以基本上在循环中从1 迭代到$nbmsg。该数字不是ID或任何东西,它只是一个索引。所以foreach my $msgnum ( 1 .. $nbmsg ) { ... } 会起作用。这也将直接对它们进行排序。您现在所拥有的以随机顺序返回 %$index 的键,因为 Perl 中的哈希未排序,并且实现细节使顺序随机。不要依赖输出的顺序,在不同的机器上会有所不同。
  • 已编辑,感谢您的帮助。 :)
  • FWIW,一个有效的 base64 块的长度是 4x 个字符,不包括空格和一些其他字符,并且用 = 字符填充以使其成为真的。在这种情况下,原始内容是 3a+1 字节,编码为 4b+2,所以最后必须有两个填充字节。

标签: perl imap


【解决方案1】:

您的消息被编码为Base64。电子邮件有MIME type 是完全正常的,尽管不是必需的。你需要解码它们。一个很好的方法是使用MIME::Base64。请注意,== 是 Base64 字符串的一部分。这是使字符串具有正确长度的填充。

use strict;
use warnings;
use MIME::Base64 'decode_base64';

my $decoded_msg = decode_base64($msg_body);

但是,您需要从这些消息对象中取出正文。文档对此含糊其辞,没有说明这些对象是什么,get 只返回原始消息。

我建议您安装Data::Printer 并使用它来转储您的$msg 对象之一。该转储将包括对象的内部结构(可能是哈希引用),以及对象具有的所有方法。这个对象可能包含一个访问器来获取已经解码的内容。如果是这种情况,您不需要自己解码。如果没有,请取出尸体并使用decode_base64 对其进行解码。


更新:我阅读了the code,它在get 方法中创建了 Net::IMAP::Simple::_message 对象。有a package definition at the top of the code。这有点复杂,但很明显。它使用行的arrayref作为对象背后的数据结构,所以我上面错了。

q( package Net::IMAP::Simple::_message;
   use overload fallback=>1, '""' => sub { local $"=""; "@{$_[0]}" };
   sub new { bless $_[1] })

再往下:

return  wantarray ? @lines : Net::IMAP::Simple::_message->new(\@lines)

所以要得到正文,你需要去掉标题字符串。转储出对象后,您应该会看到数组开头有多少元素是标题和空行。我假设索引0 是标题行,索引1 是空行。如果你不关心这些,你可以把它们扔掉。

这将改变对象。

shift @$msg; # get rid of header
shift @$msg; # get rid of empty line

my $decoded_msg = decode_base64("$msg");

【讨论】:

  • 顺便说一下,关于这个文档部分:“可选地,可以指定一个部分以获取消息的特定部分。这是消息部分的原始编码正文。该部分number 是一组由句点分隔的零个或多个部分说明符。每条消息至少有一个部分。指定“1”的一部分返回原始的编码正文。这仅在您知道标头信息(例如编码)时才有用。 " body 可以是 $imap->get($msgnum , '1.1'),我试试看
  • 刚刚看了更新,很有启发。我不再使用计算机了,但我很快就会回来尝试一切。
  • @amram 如果您没有尝试,您不应该接受答案。也许其他人会有更好的,但如果它已经被接受,他们可能会不鼓励发布它。
  • 我接受它作为回答我为什么没有我的消息内容的问题。
  • 无论如何,我试图用你的方法解码一个孤立的消息:my $decoded_msg = decode_base64("$msg");而且效果很好。
猜你喜欢
  • 2012-08-20
  • 2019-10-23
  • 1970-01-01
  • 2020-12-14
  • 2017-09-01
  • 1970-01-01
  • 2011-10-06
  • 2016-04-21
  • 2011-01-05
相关资源
最近更新 更多