Reputation: 57
After hours of searching, reading, and clawing for an answer, I come here to beg for help:
I am trying to write a client to read my Gmail with the Perl module Mail::IMAPClient. Everything so far is functional, and it works great, but when I try to get the number of emails in my "INBOX" folder, it doesn't give the correct number:
# 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";
When reading from my "INBOX" folder, assigning @msgIDs
to the commands:
$imap->search("ALL");
$imap->messages;
$imap->message_count;
All result in the same number being said to be the number of messages (1194
, to be exact) in the inbox, when there are actually 1149
.
After the number of messages is printed, the program continues with asking the user how many "headers" of recent messages they want to see (this means that if I put in "5", I would see the "Subject" and "From" header fields from the five newest messages). This code comes right after the previously shown code:
# 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);
The &read_more() subroutine works with one or two arguments, but here's the two argument version:
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);
}
}
So, if I called &read_more(1000, 5)
, I would see "Subject" and "From" header fields for message IDs 990-999. So when I call &read_more(scalar(@msgIDs), $read_num)
, I intend to see the header fields for the $read_num
latest messages. Instead, I DO NOT see any header fields for my 9 latest messages, even though I am able to read them perfectly fine in the program (I'm not showing the code for that; it would complicate things). The number of messages found doesn't change. If I received one new message, then I wouldn't be able to see the 10 latest messages. The client is stuck at message ID 1193. I already configured my Gmail settings to allow IMAP.
Is this an error in my code, or is it a problem with my Gmail configuration, or something else?
Upvotes: 3
Views: 2837
Reputation: 123461
you consider @msgID as a sequence starting with 0 and ending with message_count-1. This don't need to be the case. For instance I have currently one message but the msgID of this single message is 6. Therefore you should use the msgIDs given by search and not assume just a simple sequence.
Edit: the code uses Uid =>1 in the constructor, so search returns UIDs and get_header expectets UIDs. Changing it to Uid => 0 makes it work with sequence numbers instead.
Upvotes: 2
Reputation: 57
Fixed it myself. Okay, this requires a bit of faulty logic (this program is for personal use, anyway, so that doesn't matter).
If a email doesn't have a "From" header field in its header (that is, if a email is found without an author), than it isn't an email. So, a subroutine that can count emails until an empty "From" header field is found would correctly count the number of emails in the Inbox:
# 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;
}
So, calling &message_num ($imap)
in my code gives me a usable number of messages. It's incorrect, but it allows me to see all of my recent messages, which is what I wanted.
Upvotes: 0