BjoernD has asked for the wisdom of the Perl Monks concerning the following question:

Hello, I (Perl newbie) tried to write a script that checks the number of messages on my POP3 accounts. This is my code:
#!/usr/bin/perl use strict; use warnings; use diagnostics; use Net::POP3; use Term::ReadKey; # Read the mail accounts from a file called addresses # which resides in the script's directory open ADDRESSES, "./addresses"; # read all the lines my @addys = <ADDRESSES>; # close address file close ADDRESSES; # do the following for every address foreach my $address (@addys) { # chomp newlines chomp $address; # split address into username and hostname (my $user, my $host) = split /\s/, $address; # let the user enter his password print "Please enter the password for $user\@$host\:"; ReadMode( "noecho" ); my $pass = ReadLine(); ReadMode( "normal" ); print "\n"; # connect to host my $pop = Net::POP3->new( $host ) or do { print "Could not initialize connection.\n"; next; }; print "Connected to $host.\n"; # send USER $pop->user( $user ) or do { print "Could not send user name.\n"; next; }; print "Sent username $user.\n"; # send pass, receive number of messages my @a = $pop->pass( $pass ) or do { print "Could not send password.\n"; next; }; # print number of msg or complain about failed login if (defined $a[0]) { $pop->quit(); print "Messages: $a[0]\n"; } else { print "Login failed.\n"; } }
The script accesses a file called "addresses" where login and POP3 server are stored in the following way: <login> <pop3 server>\n <login> <pop3 server>\n etc. Generally the script does its work as long as login to the server works too. If login fails I get an error message: Use of uninitialized value in numeric eq (==) at /usr/share/perl/5.8.2/Net/POP3.pm line 302, <STDIN> line 1 (#1) The line itself is:
sub _QUIT { shift->command('QUIT')->response() == CMD_OK }
Seems like the problem is that the server after getting the wrong password closes the connection and this way $pop gets undefined? Can anyone please show me a workaround? Thank you

20031224 Edit by BazB: Changed title from 'Net::POP3'

Replies are listed 'Best First'.
Re: How to check number of messages using Net::POP3?
by Roger (Parson) on Dec 23, 2003 at 22:43 UTC
    Have you tried to use the login method to login to your POP3 Mail account. The return value is the number of messages in the mailbox, and undef if login fails.

    #!/usr/bin/perl use strict; use warnings; use diagnostics; use Net::POP3; use Term::ReadKey; # Read the mail accounts from a file called addresses # which resides in the script's directory open ADDRESSES, "./addresses"; # read all the lines my @addys = <ADDRESSES>; # close address file close ADDRESSES; # do the following for every address foreach my $address (@addys) { # split address into username and hostname my ($user, $host) = $address =~ /(\S+)\s(\S+)/; # let the user enter his password print "Please enter the password for $user\@$host\:"; ReadMode( "noecho" ); my $pass = ReadLine(); ReadMode( "normal" ); print "\n"; # connect to host my $pop = Net::POP3->new( $host ) or do { print "Could not initialize connection.\n"; next; }; print "Connected to $host.\n"; # send USER my $msg_count = $pop->login( $user, $pass ) or do { print "Could not login.\n"; next; }; # print number of msg or complain about failed login if (defined $msg_count) { $pop->quit(); print "Messages: $msg_count\n"; } else { print "Login failed.\n"; } }
      Yes I did. Didn't improve either. If you have a look in Net/POP3.pm you see that login only calls user() and pass() after each other.
        You could use the Data::Dumper module to do some inspection for you...

        use Data::Dumper; ... my $msg_count = $pop->login( $user, $pass ) or do { print "Could not login.\n"; next; }; print Dumper($msg_count);
        and see if the returned value is truly undef or not.

Re: How to check number of messages using Net::POP3?
by b10m (Vicar) on Dec 23, 2003 at 22:02 UTC
    Seems like the problem is that the server after getting the wrong password closes the connection and this way $pop gets undefined?

    No, you forget to quit and close the connection, which should be done even if there is a login failure. If you do quit and close the connection, the error message will be gone :) (just move it outside the if-statement)

    # print number of msg or complain about failed login if (defined $a[0]) { print "Messages: $a[0]\n"; } else { print "Login failed.\n"; } $pop->quit();
    --
    b10m
      This is unfortunately not the solution. Still get this error message when login fails. The message disappears if I do not use diagnostics;

        Ok, I have tested it on 3 machines now:

        1. Linux Debian
          • Perl v5.8.0
          • Net::POP3 v2.24

        2. Linux Slackware
          • Perl v5.6.0
          • Net::POP3 v2.23

        3. FreeBSD
          • Perl v5.8.0
          • Net::POP3 v2.24
        And got the following results:

        Machine Result
        1 Initially gave the same error message, but that got solved after moving $pop->quit() outside the if-statement.
        2 Initially gave the same error message, but that got solved after moving $pop->quit() outside the if-statement.
        3 Initially gave the same error message, but that got solved after moving $pop->quit() outside the if-statement.

        I tested your posted code verbatim first, and with my slight alteration afterwards. I did not take out the "use diagnostics;". So I am now curious what Perl and Net:POP3 versions you use. Oh, maybe it has anything to do with it, but I tested the script on a qpopper POP3 daemon, first with one line in "./addresses" and later with multiple lines.

        Update: now also tested with the "POP3 Server (Version 1.006d)" daemon, same result.

        --
        b10m
      The quit method in Net::POP3 calls sub _QUIT, which is going to fail if the login fails. So calling quit on a failed login is a bad idea.

        Could you please explain this, for I don't understand it. quit works pretty good if you manually emulate a POP3 client:

        $ telnet *host* 110 Trying *host*... Connected to *host*. Escape character is '^]'. +OK *host* POP3 Server (Version 1.006d) ready at <Wed Dec 24 00:29:42 +2003> user *user* +OK please send PASS command pass invalidpass -ERR invalid usercode or password, please try again quit +OK *host* POP3 Server (Version 1.006d) shutdown. Connection closed by foreign host.
        --
        b10m
Re: How to check number of messages using Net::POP3?
by duct_tape (Hermit) on Dec 23, 2003 at 22:36 UTC
    Hello

    It looks like response returns undef when it can not getline. I am assume the reason is that your POP3 server is disconnecting you once you enter a bad password. Not quite sure how to get around the warning other than patch Net::POP3 to handle that more gracefully. You can always disable warnings / diagnostics if the warning really bothers you. It's not always worthwhile to jump through hoops to avoid warnings.

    Also, here are a few things I noticed when I looked at your code.

    According to the documentation for Net::POP3, pass returns the number of messages in the mailbox. Since it returns a scalar you don't need to assign it to an array. You can do something like so:

    my $count = $pop->pass($pass);

    Also, if there are 0 messages in the mailbox pass will return 0E0 which will evaluate to true. Because of this you can bypass your check for defined as if it returned undef then you would've already caught it with your or do {....

    print "Messages: $count\n";

    Overall everything looks good! Keep up the good work!

    Regards
    Brad
Re: How to check number of messages using Net::POP3?
by shotgunefx (Parson) on Dec 23, 2003 at 23:44 UTC
    Are you sure it's not timing out? I remember having a weird problem like that a long time ago. It was a program that fed off a pop box. If it ran too long it would time out the connection.


    -Lee

    "To be civilized is to deny one's nature."
        Have you used Debug =>1, when creating the POP3 object?
        update
        Meant to reply to BjoernD, whoops.

        -Lee

        "To be civilized is to deny one's nature."