1# Net::POP3.pm 2# 3# Copyright (C) 1995-2004 Graham Barr. All rights reserved. 4# Copyright (C) 2013-2016 Steve Hay. All rights reserved. 5# This module is free software; you can redistribute it and/or modify it under 6# the same terms as Perl itself, i.e. under the terms of either the GNU General 7# Public License or the Artistic License, as specified in the F<LICENCE> file. 8 9package Net::POP3; 10 11use 5.008001; 12 13use strict; 14use warnings; 15 16use Carp; 17use IO::Socket; 18use Net::Cmd; 19use Net::Config; 20 21our $VERSION = "3.11"; 22 23# Code for detecting if we can use SSL 24my $ssl_class = eval { 25 require IO::Socket::SSL; 26 # first version with default CA on most platforms 27 no warnings 'numeric'; 28 IO::Socket::SSL->VERSION(2.007); 29} && 'IO::Socket::SSL'; 30 31my $nossl_warn = !$ssl_class && 32 'To use SSL please install IO::Socket::SSL with version>=2.007'; 33 34# Code for detecting if we can use IPv6 35my $family_key = 'Domain'; 36my $inet6_class = eval { 37 require IO::Socket::IP; 38 no warnings 'numeric'; 39 IO::Socket::IP->VERSION(0.25) || die; 40 $family_key = 'Family'; 41} && 'IO::Socket::IP' || eval { 42 require IO::Socket::INET6; 43 no warnings 'numeric'; 44 IO::Socket::INET6->VERSION(2.62); 45} && 'IO::Socket::INET6'; 46 47 48sub can_ssl { $ssl_class }; 49sub can_inet6 { $inet6_class }; 50 51our @ISA = ('Net::Cmd', $inet6_class || 'IO::Socket::INET'); 52 53sub new { 54 my $self = shift; 55 my $type = ref($self) || $self; 56 my ($host, %arg); 57 if (@_ % 2) { 58 $host = shift; 59 %arg = @_; 60 } 61 else { 62 %arg = @_; 63 $host = delete $arg{Host}; 64 } 65 my $hosts = defined $host ? [$host] : $NetConfig{pop3_hosts}; 66 my $obj; 67 68 if ($arg{SSL}) { 69 # SSL from start 70 die $nossl_warn if !$ssl_class; 71 $arg{Port} ||= 995; 72 } 73 74 $arg{Timeout} = 120 if ! defined $arg{Timeout}; 75 76 foreach my $h (@{$hosts}) { 77 $obj = $type->SUPER::new( 78 PeerAddr => ($host = $h), 79 PeerPort => $arg{Port} || 'pop3(110)', 80 Proto => 'tcp', 81 $family_key => $arg{Domain} || $arg{Family}, 82 LocalAddr => $arg{LocalAddr}, 83 LocalPort => exists($arg{ResvPort}) ? $arg{ResvPort} : $arg{LocalPort}, 84 Timeout => $arg{Timeout}, 85 ) 86 and last; 87 } 88 89 return 90 unless defined $obj; 91 92 ${*$obj}{'net_pop3_arg'} = \%arg; 93 ${*$obj}{'net_pop3_host'} = $host; 94 if ($arg{SSL}) { 95 Net::POP3::_SSL->start_SSL($obj,%arg) or return; 96 } 97 98 $obj->autoflush(1); 99 $obj->debug(exists $arg{Debug} ? $arg{Debug} : undef); 100 101 unless ($obj->response() == CMD_OK) { 102 $obj->close(); 103 return; 104 } 105 106 ${*$obj}{'net_pop3_banner'} = $obj->message; 107 108 $obj; 109} 110 111 112sub host { 113 my $me = shift; 114 ${*$me}{'net_pop3_host'}; 115} 116 117## 118## We don't want people sending me their passwords when they report problems 119## now do we :-) 120## 121 122 123sub debug_text { $_[2] =~ /^(pass|rpop)/i ? "$1 ....\n" : $_[2]; } 124 125 126sub login { 127 @_ >= 1 && @_ <= 3 or croak 'usage: $pop3->login( USER, PASS )'; 128 my ($me, $user, $pass) = @_; 129 130 if (@_ <= 2) { 131 ($user, $pass) = $me->_lookup_credentials($user); 132 } 133 134 $me->user($user) 135 and $me->pass($pass); 136} 137 138sub starttls { 139 my $self = shift; 140 $ssl_class or die $nossl_warn; 141 $self->_STLS or return; 142 Net::POP3::_SSL->start_SSL($self, 143 %{ ${*$self}{'net_pop3_arg'} }, # (ssl) args given in new 144 @_ # more (ssl) args 145 ) or return; 146 return 1; 147} 148 149sub apop { 150 @_ >= 1 && @_ <= 3 or croak 'usage: $pop3->apop( USER, PASS )'; 151 my ($me, $user, $pass) = @_; 152 my $banner; 153 my $md; 154 155 if (eval { local $SIG{__DIE__}; require Digest::MD5 }) { 156 $md = Digest::MD5->new(); 157 } 158 elsif (eval { local $SIG{__DIE__}; require MD5 }) { 159 $md = MD5->new(); 160 } 161 else { 162 carp "You need to install Digest::MD5 or MD5 to use the APOP command"; 163 return; 164 } 165 166 return 167 unless ($banner = (${*$me}{'net_pop3_banner'} =~ /(<.*>)/)[0]); 168 169 if (@_ <= 2) { 170 ($user, $pass) = $me->_lookup_credentials($user); 171 } 172 173 $md->add($banner, $pass); 174 175 return 176 unless ($me->_APOP($user, $md->hexdigest)); 177 178 $me->_get_mailbox_count(); 179} 180 181 182sub user { 183 @_ == 2 or croak 'usage: $pop3->user( USER )'; 184 $_[0]->_USER($_[1]) ? 1 : undef; 185} 186 187 188sub pass { 189 @_ == 2 or croak 'usage: $pop3->pass( PASS )'; 190 191 my ($me, $pass) = @_; 192 193 return 194 unless ($me->_PASS($pass)); 195 196 $me->_get_mailbox_count(); 197} 198 199 200sub reset { 201 @_ == 1 or croak 'usage: $obj->reset()'; 202 203 my $me = shift; 204 205 return 0 206 unless ($me->_RSET); 207 208 if (defined ${*$me}{'net_pop3_mail'}) { 209 local $_; 210 foreach (@{${*$me}{'net_pop3_mail'}}) { 211 delete $_->{'net_pop3_deleted'}; 212 } 213 } 214} 215 216 217sub last { 218 @_ == 1 or croak 'usage: $obj->last()'; 219 220 return 221 unless $_[0]->_LAST && $_[0]->message =~ /(\d+)/; 222 223 return $1; 224} 225 226 227sub top { 228 @_ == 2 || @_ == 3 or croak 'usage: $pop3->top( MSGNUM [, NUMLINES ])'; 229 my $me = shift; 230 231 return 232 unless $me->_TOP($_[0], $_[1] || 0); 233 234 $me->read_until_dot; 235} 236 237 238sub popstat { 239 @_ == 1 or croak 'usage: $pop3->popstat()'; 240 my $me = shift; 241 242 return () 243 unless $me->_STAT && $me->message =~ /(\d+)\D+(\d+)/; 244 245 ($1 || 0, $2 || 0); 246} 247 248 249sub list { 250 @_ == 1 || @_ == 2 or croak 'usage: $pop3->list( [ MSGNUM ] )'; 251 my $me = shift; 252 253 return 254 unless $me->_LIST(@_); 255 256 if (@_) { 257 $me->message =~ /\d+\D+(\d+)/; 258 return $1 || undef; 259 } 260 261 my $info = $me->read_until_dot 262 or return; 263 264 my %hash = map { (/(\d+)\D+(\d+)/) } @$info; 265 266 return \%hash; 267} 268 269 270sub get { 271 @_ == 2 or @_ == 3 or croak 'usage: $pop3->get( MSGNUM [, FH ])'; 272 my $me = shift; 273 274 return 275 unless $me->_RETR(shift); 276 277 $me->read_until_dot(@_); 278} 279 280 281sub getfh { 282 @_ == 2 or croak 'usage: $pop3->getfh( MSGNUM )'; 283 my $me = shift; 284 285 return unless $me->_RETR(shift); 286 return $me->tied_fh; 287} 288 289 290sub delete { 291 @_ == 2 or croak 'usage: $pop3->delete( MSGNUM )'; 292 my $me = shift; 293 return 0 unless $me->_DELE(@_); 294 ${*$me}{'net_pop3_deleted'} = 1; 295} 296 297 298sub uidl { 299 @_ == 1 || @_ == 2 or croak 'usage: $pop3->uidl( [ MSGNUM ] )'; 300 my $me = shift; 301 my $uidl; 302 303 $me->_UIDL(@_) 304 or return; 305 if (@_) { 306 $uidl = ($me->message =~ /\d+\s+([\041-\176]+)/)[0]; 307 } 308 else { 309 my $ref = $me->read_until_dot 310 or return; 311 $uidl = {}; 312 foreach my $ln (@$ref) { 313 my ($msg, $uid) = $ln =~ /^\s*(\d+)\s+([\041-\176]+)/; 314 $uidl->{$msg} = $uid; 315 } 316 } 317 return $uidl; 318} 319 320 321sub ping { 322 @_ == 2 or croak 'usage: $pop3->ping( USER )'; 323 my $me = shift; 324 325 return () unless $me->_PING(@_) && $me->message =~ /(\d+)\D+(\d+)/; 326 327 ($1 || 0, $2 || 0); 328} 329 330 331sub _lookup_credentials { 332 my ($me, $user) = @_; 333 334 require Net::Netrc; 335 336 $user ||= eval { local $SIG{__DIE__}; (getpwuid($>))[0] } 337 || $ENV{NAME} 338 || $ENV{USER} 339 || $ENV{LOGNAME}; 340 341 my $m = Net::Netrc->lookup(${*$me}{'net_pop3_host'}, $user); 342 $m ||= Net::Netrc->lookup(${*$me}{'net_pop3_host'}); 343 344 my $pass = $m 345 ? $m->password || "" 346 : ""; 347 348 ($user, $pass); 349} 350 351 352sub _get_mailbox_count { 353 my ($me) = @_; 354 my $ret = ${*$me}{'net_pop3_count'} = 355 ($me->message =~ /(\d+)\s+message/io) ? $1 : ($me->popstat)[0]; 356 357 $ret ? $ret : "0E0"; 358} 359 360 361sub _STAT { shift->command('STAT' )->response() == CMD_OK } 362sub _LIST { shift->command('LIST', @_)->response() == CMD_OK } 363sub _RETR { shift->command('RETR', $_[0])->response() == CMD_OK } 364sub _DELE { shift->command('DELE', $_[0])->response() == CMD_OK } 365sub _NOOP { shift->command('NOOP' )->response() == CMD_OK } 366sub _RSET { shift->command('RSET' )->response() == CMD_OK } 367sub _QUIT { shift->command('QUIT' )->response() == CMD_OK } 368sub _TOP { shift->command( 'TOP', @_)->response() == CMD_OK } 369sub _UIDL { shift->command('UIDL', @_)->response() == CMD_OK } 370sub _USER { shift->command('USER', $_[0])->response() == CMD_OK } 371sub _PASS { shift->command('PASS', $_[0])->response() == CMD_OK } 372sub _APOP { shift->command('APOP', @_)->response() == CMD_OK } 373sub _PING { shift->command('PING', $_[0])->response() == CMD_OK } 374sub _RPOP { shift->command('RPOP', $_[0])->response() == CMD_OK } 375sub _LAST { shift->command('LAST' )->response() == CMD_OK } 376sub _CAPA { shift->command('CAPA' )->response() == CMD_OK } 377sub _STLS { shift->command("STLS", )->response() == CMD_OK } 378 379 380sub quit { 381 my $me = shift; 382 383 $me->_QUIT; 384 $me->close; 385} 386 387 388sub DESTROY { 389 my $me = shift; 390 391 if (defined fileno($me) and ${*$me}{'net_pop3_deleted'}) { 392 $me->reset; 393 $me->quit; 394 } 395} 396 397## 398## POP3 has weird responses, so we emulate them to look the same :-) 399## 400 401 402sub response { 403 my $cmd = shift; 404 my $str = $cmd->getline() or return; 405 my $code = "500"; 406 407 $cmd->debug_print(0, $str) 408 if ($cmd->debug); 409 410 if ($str =~ s/^\+OK\s*//io) { 411 $code = "200"; 412 } 413 elsif ($str =~ s/^\+\s*//io) { 414 $code = "300"; 415 } 416 else { 417 $str =~ s/^-ERR\s*//io; 418 } 419 420 ${*$cmd}{'net_cmd_resp'} = [$str]; 421 ${*$cmd}{'net_cmd_code'} = $code; 422 423 substr($code, 0, 1); 424} 425 426 427sub capa { 428 my $this = shift; 429 my ($capa, %capabilities); 430 431 # Fake a capability here 432 $capabilities{APOP} = '' if ($this->banner() =~ /<.*>/); 433 434 if ($this->_CAPA()) { 435 $capabilities{CAPA} = 1; 436 $capa = $this->read_until_dot(); 437 %capabilities = (%capabilities, map {/^\s*(\S+)\s*(.*)/} @$capa); 438 } 439 else { 440 441 # Check AUTH for SASL capabilities 442 if ($this->command('AUTH')->response() == CMD_OK) { 443 my $mechanism = $this->read_until_dot(); 444 $capabilities{SASL} = join " ", map {m/([A-Z0-9_-]+)/} @{$mechanism}; 445 } 446 } 447 448 return ${*$this}{'net_pop3e_capabilities'} = \%capabilities; 449} 450 451 452sub capabilities { 453 my $this = shift; 454 455 ${*$this}{'net_pop3e_capabilities'} || $this->capa; 456} 457 458 459sub auth { 460 my ($self, $username, $password) = @_; 461 462 eval { 463 require MIME::Base64; 464 require Authen::SASL; 465 } or $self->set_status(500, ["Need MIME::Base64 and Authen::SASL todo auth"]), return 0; 466 467 my $capa = $self->capa; 468 my $mechanisms = $capa->{SASL} || 'CRAM-MD5'; 469 470 my $sasl; 471 472 if (ref($username) and UNIVERSAL::isa($username, 'Authen::SASL')) { 473 $sasl = $username; 474 my $user_mech = $sasl->mechanism || ''; 475 my @user_mech = split(/\s+/, $user_mech); 476 my %user_mech; 477 @user_mech{@user_mech} = (); 478 479 my @server_mech = split(/\s+/, $mechanisms); 480 my @mech = @user_mech 481 ? grep { exists $user_mech{$_} } @server_mech 482 : @server_mech; 483 unless (@mech) { 484 $self->set_status( 485 500, 486 [ 'Client SASL mechanisms (', 487 join(', ', @user_mech), 488 ') do not match the SASL mechnism the server announces (', 489 join(', ', @server_mech), ')', 490 ] 491 ); 492 return 0; 493 } 494 495 $sasl->mechanism(join(" ", @mech)); 496 } 497 else { 498 die "auth(username, password)" if not length $username; 499 $sasl = Authen::SASL->new( 500 mechanism => $mechanisms, 501 callback => { 502 user => $username, 503 pass => $password, 504 authname => $username, 505 } 506 ); 507 } 508 509 # We should probably allow the user to pass the host, but I don't 510 # currently know and SASL mechanisms that are used by smtp that need it 511 my ($hostname) = split /:/, ${*$self}{'net_pop3_host'}; 512 my $client = eval { $sasl->client_new('pop', $hostname, 0) }; 513 514 unless ($client) { 515 my $mech = $sasl->mechanism; 516 $self->set_status( 517 500, 518 [ " Authen::SASL failure: $@", 519 '(please check if your local Authen::SASL installation', 520 "supports mechanism '$mech'" 521 ] 522 ); 523 return 0; 524 } 525 526 my ($token) = $client->client_start 527 or do { 528 my $mech = $client->mechanism; 529 $self->set_status( 530 500, 531 [ ' Authen::SASL failure: $client->client_start ', 532 "mechanism '$mech' hostname #$hostname#", 533 $client->error 534 ] 535 ); 536 return 0; 537 }; 538 539 # We don't support sasl mechanisms that encrypt the socket traffic. 540 # todo that we would really need to change the ISA hierarchy 541 # so we don't inherit from IO::Socket, but instead hold it in an attribute 542 543 my @cmd = ("AUTH", $client->mechanism); 544 my $code; 545 546 push @cmd, MIME::Base64::encode_base64($token, '') 547 if defined $token and length $token; 548 549 while (($code = $self->command(@cmd)->response()) == CMD_MORE) { 550 551 my ($token) = $client->client_step(MIME::Base64::decode_base64(($self->message)[0])) or do { 552 $self->set_status( 553 500, 554 [ ' Authen::SASL failure: $client->client_step ', 555 "mechanism '", $client->mechanism, " hostname #$hostname#, ", 556 $client->error 557 ] 558 ); 559 return 0; 560 }; 561 562 @cmd = (MIME::Base64::encode_base64(defined $token ? $token : '', '')); 563 } 564 565 $code == CMD_OK; 566} 567 568 569sub banner { 570 my $this = shift; 571 572 return ${*$this}{'net_pop3_banner'}; 573} 574 575{ 576 package Net::POP3::_SSL; 577 our @ISA = ( $ssl_class ? ($ssl_class):(), 'Net::POP3' ); 578 sub starttls { die "POP3 connection is already in SSL mode" } 579 sub start_SSL { 580 my ($class,$pop3,%arg) = @_; 581 delete @arg{ grep { !m{^SSL_} } keys %arg }; 582 ( $arg{SSL_verifycn_name} ||= $pop3->host ) 583 =~s{(?<!:):[\w()]+$}{}; # strip port 584 $arg{SSL_hostname} = $arg{SSL_verifycn_name} 585 if ! defined $arg{SSL_hostname} && $class->can_client_sni; 586 $arg{SSL_verifycn_scheme} ||= 'pop3'; 587 my $ok = $class->SUPER::start_SSL($pop3,%arg); 588 $@ = $ssl_class->errstr if !$ok; 589 return $ok; 590 } 591} 592 593 594 5951; 596 597__END__ 598 599=head1 NAME 600 601Net::POP3 - Post Office Protocol 3 Client class (RFC1939) 602 603=head1 SYNOPSIS 604 605 use Net::POP3; 606 607 # Constructors 608 $pop = Net::POP3->new('pop3host'); 609 $pop = Net::POP3->new('pop3host', Timeout => 60); 610 $pop = Net::POP3->new('pop3host', SSL => 1, Timeout => 60); 611 612 if ($pop->login($username, $password) > 0) { 613 my $msgnums = $pop->list; # hashref of msgnum => size 614 foreach my $msgnum (keys %$msgnums) { 615 my $msg = $pop->get($msgnum); 616 print @$msg; 617 $pop->delete($msgnum); 618 } 619 } 620 621 $pop->quit; 622 623=head1 DESCRIPTION 624 625This module implements a client interface to the POP3 protocol, enabling 626a perl5 application to talk to POP3 servers. This documentation assumes 627that you are familiar with the POP3 protocol described in RFC1939. 628With L<IO::Socket::SSL> installed it also provides support for implicit and 629explicit TLS encryption, i.e. POP3S or POP3+STARTTLS. 630 631A new Net::POP3 object must be created with the I<new> method. Once 632this has been done, all POP3 commands are accessed via method calls 633on the object. 634 635The Net::POP3 class is a subclass of Net::Cmd and (depending on avaibility) of 636IO::Socket::IP, IO::Socket::INET6 or IO::Socket::INET. 637 638 639=head1 CONSTRUCTOR 640 641=over 4 642 643=item new ( [ HOST ] [, OPTIONS ] ) 644 645This is the constructor for a new Net::POP3 object. C<HOST> is the 646name of the remote host to which an POP3 connection is required. 647 648C<HOST> is optional. If C<HOST> is not given then it may instead be 649passed as the C<Host> option described below. If neither is given then 650the C<POP3_Hosts> specified in C<Net::Config> will be used. 651 652C<OPTIONS> are passed in a hash like fashion, using key and value pairs. 653Possible options are: 654 655B<Host> - POP3 host to connect to. It may be a single scalar, as defined for 656the C<PeerAddr> option in L<IO::Socket::INET>, or a reference to 657an array with hosts to try in turn. The L</host> method will return the value 658which was used to connect to the host. 659 660B<Port> - port to connect to. 661Default - 110 for plain POP3 and 995 for POP3s (direct SSL). 662 663B<SSL> - If the connection should be done from start with SSL, contrary to later 664upgrade with C<starttls>. 665You can use SSL arguments as documented in L<IO::Socket::SSL>, but it will 666usually use the right arguments already. 667 668B<LocalAddr> and B<LocalPort> - These parameters are passed directly 669to IO::Socket to allow binding the socket to a specific local address and port. 670For compatibility with older versions B<ResvPort> can be used instead of 671B<LocalPort>. 672 673B<Domain> - This parameter is passed directly to IO::Socket and makes it 674possible to enforce IPv4 connections even if L<IO::Socket::IP> is used as super 675class. Alternatively B<Family> can be used. 676 677B<Timeout> - Maximum time, in seconds, to wait for a response from the 678POP3 server (default: 120) 679 680B<Debug> - Enable debugging information 681 682=back 683 684=head1 METHODS 685 686Unless otherwise stated all methods return either a I<true> or I<false> 687value, with I<true> meaning that the operation was a success. When a method 688states that it returns a value, failure will be returned as I<undef> or an 689empty list. 690 691C<Net::POP3> inherits from C<Net::Cmd> so methods defined in C<Net::Cmd> may 692be used to send commands to the remote POP3 server in addition to the methods 693documented here. 694 695=over 4 696 697=item host () 698 699Returns the value used by the constructor, and passed to IO::Socket::INET, 700to connect to the host. 701 702=item auth ( USERNAME, PASSWORD ) 703 704Attempt SASL authentication. 705 706=item user ( USER ) 707 708Send the USER command. 709 710=item pass ( PASS ) 711 712Send the PASS command. Returns the number of messages in the mailbox. 713 714=item login ( [ USER [, PASS ]] ) 715 716Send both the USER and PASS commands. If C<PASS> is not given the 717C<Net::POP3> uses C<Net::Netrc> to lookup the password using the host 718and username. If the username is not specified then the current user name 719will be used. 720 721Returns the number of messages in the mailbox. However if there are no 722messages on the server the string C<"0E0"> will be returned. This is 723will give a true value in a boolean context, but zero in a numeric context. 724 725If there was an error authenticating the user then I<undef> will be returned. 726 727=item starttls ( SSLARGS ) 728 729Upgrade existing plain connection to SSL. 730You can use SSL arguments as documented in L<IO::Socket::SSL>, but it will 731usually use the right arguments already. 732 733=item apop ( [ USER [, PASS ]] ) 734 735Authenticate with the server identifying as C<USER> with password C<PASS>. 736Similar to L</login>, but the password is not sent in clear text. 737 738To use this method you must have the Digest::MD5 or the MD5 module installed, 739otherwise this method will return I<undef>. 740 741=item banner () 742 743Return the sever's connection banner 744 745=item capa () 746 747Return a reference to a hash of the capabilities of the server. APOP 748is added as a pseudo capability. Note that I've been unable to 749find a list of the standard capability values, and some appear to 750be multi-word and some are not. We make an attempt at intelligently 751parsing them, but it may not be correct. 752 753=item capabilities () 754 755Just like capa, but only uses a cache from the last time we asked 756the server, so as to avoid asking more than once. 757 758=item top ( MSGNUM [, NUMLINES ] ) 759 760Get the header and the first C<NUMLINES> of the body for the message 761C<MSGNUM>. Returns a reference to an array which contains the lines of text 762read from the server. 763 764=item list ( [ MSGNUM ] ) 765 766If called with an argument the C<list> returns the size of the message 767in octets. 768 769If called without arguments a reference to a hash is returned. The 770keys will be the C<MSGNUM>'s of all undeleted messages and the values will 771be their size in octets. 772 773=item get ( MSGNUM [, FH ] ) 774 775Get the message C<MSGNUM> from the remote mailbox. If C<FH> is not given 776then get returns a reference to an array which contains the lines of 777text read from the server. If C<FH> is given then the lines returned 778from the server are printed to the filehandle C<FH>. 779 780=item getfh ( MSGNUM ) 781 782As per get(), but returns a tied filehandle. Reading from this 783filehandle returns the requested message. The filehandle will return 784EOF at the end of the message and should not be reused. 785 786=item last () 787 788Returns the highest C<MSGNUM> of all the messages accessed. 789 790=item popstat () 791 792Returns a list of two elements. These are the number of undeleted 793elements and the size of the mbox in octets. 794 795=item ping ( USER ) 796 797Returns a list of two elements. These are the number of new messages 798and the total number of messages for C<USER>. 799 800=item uidl ( [ MSGNUM ] ) 801 802Returns a unique identifier for C<MSGNUM> if given. If C<MSGNUM> is not 803given C<uidl> returns a reference to a hash where the keys are the 804message numbers and the values are the unique identifiers. 805 806=item delete ( MSGNUM ) 807 808Mark message C<MSGNUM> to be deleted from the remote mailbox. All messages 809that are marked to be deleted will be removed from the remote mailbox 810when the server connection closed. 811 812=item reset () 813 814Reset the status of the remote POP3 server. This includes resetting the 815status of all messages to not be deleted. 816 817=item quit () 818 819Quit and close the connection to the remote POP3 server. Any messages marked 820as deleted will be deleted from the remote mailbox. 821 822=item can_inet6 () 823 824Returns whether we can use IPv6. 825 826=item can_ssl () 827 828Returns whether we can use SSL. 829 830=back 831 832=head1 NOTES 833 834If a C<Net::POP3> object goes out of scope before C<quit> method is called 835then the C<reset> method will called before the connection is closed. This 836means that any messages marked to be deleted will not be. 837 838=head1 SEE ALSO 839 840L<Net::Netrc>, 841L<Net::Cmd>, 842L<IO::Socket::SSL> 843 844=head1 AUTHOR 845 846Graham Barr E<lt>F<gbarr@pobox.com>E<gt>. 847 848Steve Hay E<lt>F<shay@cpan.org>E<gt> is now maintaining libnet as of version 8491.22_02. 850 851=head1 COPYRIGHT 852 853Copyright (C) 1995-2004 Graham Barr. All rights reserved. 854 855Copyright (C) 2013-2016 Steve Hay. All rights reserved. 856 857=head1 LICENCE 858 859This module is free software; you can redistribute it and/or modify it under the 860same terms as Perl itself, i.e. under the terms of either the GNU General Public 861License or the Artistic License, as specified in the F<LICENCE> file. 862 863=cut 864