Beefy Boxes and Bandwidth Generously Provided by pair Networks
Come for the quick hacks, stay for the epiphanies.

Trapping server responses with Net::SMTP

by fivefiftyone (Acolyte)
on Oct 21, 2008 at 17:59 UTC ( [id://718552]=perlmeditation: print w/replies, xml ) Need Help??

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 => '', Hello => '', Timeout => 30, Debug => 0); # Talk to the server $smtp->mail("postmaster\", Size => 20971520) or die "Oops. Server said ", $smtp->code(), " ", $smtp->message(); $smtp->to("youthere\") 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\", 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...

Replies are listed 'Best First'.
Re: Trapping server responses with Net::SMTP
by rhesa (Vicar) on Oct 21, 2008 at 21:11 UTC
    instead of
    if ( $smtp->status() =~ /^[45]$/ ) {
    you could use
    if ( ! $smtp->ok ) {
      which status value indicates success? which indicate failure (other than 4/5)? I tried $smtp->ok and it did not seem to accurately reflect success/failure.

Log In?

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlmeditation [id://718552]
Approved by Arunbear
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others sharing their wisdom with the Monastery: (2)
As of 2024-06-12 15:45 GMT
Find Nodes?
    Voting Booth?

    No recent polls found

    erzuuli‥ 🛈The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.