Perl: Mail::IMAPClient与Gmail配合使用无法读取新邮件。

3
经过数小时的搜索、阅读和苦苦追寻,我来到这里请求帮助:

我正在尝试使用Perl模块Mail::IMAPClient编写一个客户端来读取我的Gmail。到目前为止一切都很正常,它运行得非常好,但是当我尝试获取“收件箱”文件夹中的电子邮件数量时,它没有给出正确的数字:
# initialize the IMAP object
$imap = Mail::IMAPClient->new ( Server => 'imap.gmail.com',
                                User => $username,
                                Password => $password,
                                Port => 993,
                                Ssl => 1,
                                Uid => 1 )
or die "Could not connect to server, terminating...\n";

# find which folder to read from
print "Mailboxes: ".  join(", ", $imap->folders) . "\n";
print "Folder to use: ";
chomp (my $folder = <STDIN>);
$imap->select($folder) or die "select() failed, terminating...\n";

# get message IDs and number of messages
my @msgIDs = $imap->search("ALL");
print scalar(@msgIDs) . " message(s) found in mailbox.\n";

当从我的“收件箱”文件夹中读取时,将@msgIDs分配给命令:

$imap->search("ALL");
$imap->messages;
$imap->message_count;

所有结果都显示收件箱中有相同数量的消息(确切地说是1194条),但实际上只有1149条。

打印出消息数量后,程序继续询问用户想要查看多少最新消息的“头部”(这意味着如果我输入“5”,我将看到最新五条消息的“主题”和“发件人”头字段)。此代码紧随前面显示的代码之后:

# get number of messages to read (so the entire inbox isn't looked at)
print "Read how many? ";
chomp (my $read_num = <STDIN>);

# read the original number of headers requested
&read_more (scalar(@msgIDs), $read_num);

&read_more()子例程可以使用一个或两个参数,但这是两个参数版本:

if (@_ == 2) {
        # if an empty string was passed
        if ( $_[1] eq "" ) {
                $_[1] = 0;
        }

        # print $_[1] headers behind $_[0]
        foreach ( ($_[0]-$_[1])..($_[0]-1) ) {

                my $from = $imap->get_header ($_, "from");
                my $subject = $imap->get_header ($_, "subject");

                (printf "%d: %s\n", $_, $from);
                (printf "%d: %s\n\n", $_, $subject);
         }
}

因此,如果我调用 &read_more(1000, 5),我将看到消息ID为990-999的主题和发件人头字段。因此,当我调用 &read_more(scalar(@msgIDs), $read_num) 时,我打算查看最新$read_num条消息的标题字段。然而,尽管我能够在程序中完美地读取它们(我没有展示代码;那会让事情变得复杂),但我却没有看到我最新9条消息的任何标题字段。找到的消息数量不会改变。如果我收到一条新消息,那么我将无法看到最新的10条消息。客户端停留在消息ID 1193。我已经配置了我的Gmail设置以允许IMAP。

这是我的代码错误,还是我的Gmail配置问题,或者是其他什么问题?

2个回答

2

您认为@msgID是从0开始,以message_count-1结束的序列。但这不一定是这样的。例如,我目前只有一条消息,但这个单一消息的msgID是6。因此,您应该使用搜索给出的msgID,而不仅仅是一个简单的序列。

编辑:代码在构造函数中使用Uid => 1,因此搜索返回UID,并且get_header期望UID。将其更改为Uid => 0,使其可以使用序列号。


IMAP 中的邮件 ID 是连续的吗?还是 Perl 模块在后台使用 UID? - Max
我的模块选项是使用UID,很多子程序都依赖于它,所以我不能更改它。 - trifork
@Steffen Ullrich:我明白,但$imap->search("ALL")返回一个列出消息ID的数组(或数组引用,但那是另一回事)。我尝试在标量上下文中使用此数组,应该会给我数组中元素的数量,这应该是消息的数量。但它不是,导致了问题。 - trifork
我想我找到了真正的问题:你在构造函数中设置了Uid => 1,这意味着搜索、get_header等所有操作都基于UID而不是序列号。将其更改为Uid => 0,则使用序列号而非UID。 - Steffen Ullrich
经过更多的欺骗和许多眼泪后,我相信你是对的,我的朋友。 - trifork

0

我自己解决了。好的,这需要一些错误的逻辑(反正这个程序是为个人使用的,所以无所谓)。
如果一个电子邮件在其头部没有“发件人”头字段(也就是说,如果找到一个没有作者的电子邮件),那么它就不是电子邮件。因此,一个可以计算电子邮件数量直到找到空的“发件人”头字段的子例程将正确计算收件箱中的电子邮件数量:

# the only argument is the IMAP object, that allows communication
sub message_num {

        # there's always going to be at least this many messages, so guess here
        my @guess = $_[0]->search("ALL");

        # get the guess in scalar format so we can count with it
        my $i = scalar (@guess);

        # while the "from" headers are defined
        while ( defined ($_[0]->get_header ($i, "from")) ) {
                # count the messages past what the guess said
                $i++;
        }

        # return that count
        $i;
}

所以,在我的代码中调用&message_num ($imap)会给我一个可用的邮件数量。虽然这个数字不正确,但它让我能够看到我最近的所有邮件,这正是我想要的。

如果有人有获取真实消息数量的方法,我会非常感激。 - trifork

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