Net::FTP is actually part of the libnet distribution.
The module is actually pretty solid, except that you have to check the return codes after every call. (I'm not a real fan of that style of code.) This is done by calling $ftp->ok() after every other $ftp call. The actual message is in two parts, code() and message(). So you end up doing:
in reply to net::ftp please
I usually write a status method that retrieves and prints the status messages regardless of any errors, and then hiccups when not $ftp->ok(). So my code reads $ftp->func(); check( $ftp ); over and over again. But the end result is well worth it.
my $ftpSite = "ftp.somesite.net";
my $username = "...";
my $password = "...";
my $ftp = Net::FTP->new( $ftpSite )
or die "No connect to '$ftpSite' : $@";
$ftp->login( $username, $password );
die $ftp->code(), ": ", $ftp->message() unless $ftp->ok();
# and so on...
I hope that helps.