http://www.perlmonks.org?node_id=718552

I work for an ISP, managing a large number of mail servers dedicated to combating spam and providing content filtering solutions to our customers. During the course of an average day, I field numerous queries regarding the inner workings of mail servers from our support desk guys.

I decided to combat this by writing a Perl script which uses Net::SMTP to talk to mail servers, and spit out human readable text in place of gibberish like EXPN, VRFY and that absolute monster, SIZE, and convert RFC1893 documented errors into language that our techs can forward to customers. About 10 minutes into development, I realised that this is a project doomed to failure, but figured that playing with it would be a fun Perl learning curve anyway. A major plus in all this was that it answered a major issue I've had with writing mail scripts for a long while now.

Something that has always bugged me about Net::SMTP is the fact that I could never find a way of proactively trapping the response codes from the servers. It turns out that months of writing SMTP orientated scripts, and months of setting Debug => 1 were in vain, as the answer lay in two methods provided by Net::SMTP's parent, Net::Cmd. My butt still hurts from the vigorous kicking I administered myself after finding these:
Net::Cmd->code() Net::Cmd->message()
Yup. It's that easy. Let's take a look in context:
# Create ourselves an SMTP object my $smtp = Net::SMTP->new( Host => 'some.mailserver.de', Hello => 'my.mailserver.co.za', Timeout => 30, Debug => 0); # Talk to the server $smtp->mail("postmaster\@mailserver.co.za", Size => 20971520) or die "Oops. Server said ", $smtp->code(), " ", $smtp->message(); $smtp->to("youthere\@mailserver.de") or die "Error on RCPT TO: ", $smtp->code(), " ", $smtp->message(); $smtp->quit;
That will ensure that if an error occurs, the script will die and print out the offending error code, instead of blithely continuing as Net::SMTP normally would.

Considering my original objective, you wouldn't necessarily want to kill off the script as the error code is returned, but search for an error, and produce a pretty line explaining what had gone wrong. You'd be most interested in 4.x.x and 5.x.x errors, so you could roll out another Net::Cmd method, status():
$smtp->mail("postmaster\@mailserver.co.za", Size => 52428800); if ( $smtp->status() =~ /^[45]$/ ) { # informative error here exit(1); }
The status() method returns the first digit of the error code, allowing for a simple regex to look for an error, which you can expound upon at will. For example, I might be on the lookout for a very specific error from a specific brand of server regarding a mail size limitation:
if ( $smtp->status() =~ /^[45]$/ ) { if ( $smtp->message() eq "size limit exceeded" ) { print "Server returned a fatal error:\n"; print $smtp->code(), " ", $smtp->message(), "\n"; print "The message is too big. Boo-hoo\n"; } }
Not necessarily the best, but hey, it illustrates the point.

This, for all its simplicity, was a joy to discover. I'm continuing on my "An SMTP Script For Those Oblivious To The Existence Of RFC's And Who Are The Reason I Own A Shirt That Has RTFM Printed In Large White Letters Upon It". I ultimately fear, based the ambiguous nature of response codes that I will fail, insane, wretched and alone. Results, should I have any, will be posted here. Failing that, I trust that this little pointer helps others who turn to Net::SMTP when they need some sweet mail server interaction to brighten up their day.

Good grief, I need help! I enjoy mail waaaaaaaaay too much...