Resolving a Bad Hostname Error in Net::SMTP Perl Module
This page describes how I debugged some issues being experienced with
the Net::SMTP perl module, and how the issue was eventually resolved.
Background Information
Web Environment
I have a photography blog hosted on a shared linux webserver
in a data centre, and one of the features it supports
is email notification whenever someone leaves a comment.
The blog is coded in Perl, and uses the
Net::SMTP perl module to
send the email notifications.
When calling the Net::SMTP module, I specify the hostname of a mailserver
that it uses to send the email. It's important to note that the mailserver is in a different
data centre than the webserver (ie, the mailserver software is not running on the same
box as the webserver software).
Symptoms of the Issue
In the past few weeks, I had noticed that occasionally I wouldn't receive
an email when someone left a comment.
A friendly visitor emailed me recently, to let me know that he tried to leave a comment,
he saw a "500 Internal Server Error" page after submitting the comment.
His comment had been saved, but the email notification had failed, and
the code on the webserver that was attempting to send the email notification
had failed, causing the 500 error.
A check of the apache error log on the webserver showed:
[Sun Sep 21 08:53:39 2008] [error] [client a.b.c.d] Can't call method "auth" on an
undefined value at /path/blog/plugins/feedback line 897, <GEN> line 200.
This appeared to indicate the error was being encountered during authentication
to the mailserver by the Net::SMTP module.
Initial Investigation
Checking the Code
The first action was to check the code in my blog software that was attempting
to send the notification email. Here's a snippet of code:
# define parameters for sending email
my $smtp_server = "mail.server.hostname";
my $address = "me@my.domain.name";
my $pwd = "mail_password";
# load modules
require Net::SMTP;
Net::SMTP->import;
# create instance of module, specifying mailserver
my $smtp = Net::SMTP->new($smtp_server);
# login to mailserver if password is specified
if ($pwd)
* { $smtp->auth ($address, $pwd); }
$smtp->mail($address) or warn "net::smtp failed to set mail address\n";
....
I've highlighted the line referenced in the error mentioned earlier with
a red *, and this is the line attempting to call
the auth method of the Net::SMTP module.
However, the error specified that the auth method was
being called on an undefined value, which indicated the Net::SMTP module
was either failing to load, or the code was failing to create a new instance of it.
Add Error Handling
I added some error handling around the code that attempted to load the Net::SMTP
module and create a new instance of it, so I could determine exactly where it was failing.
# load modules
require Net::SMTP or warn "feedback: net::smtp failed to do require\n";
Net::SMTP->import;
# create instance of module, specifying mailserver
my $smtp = Net::SMTP->new($smtp_server)
or warn "feedback: net::smtp failed to create object ($!; $@)\n";
(Note that for some reason, the Net::SMTP->import; line
always returns false, so I removed the error handling initially added to it, as it
wasn't useful.)
The error handling ensures any issues with the module loading, or creation of a new
instance, would be logged, along with the error details (as contained in
$! and $@).
Identifying Where The Problem Is Occurring
Reproduce The Problem
While attempting to reproduce the problem (by repeatedly submitting comments on a blog post),
I noticed that the error occurred approximately once in ten attempts, with the other
nine attempts to send an email succeeding.
Error Details
When the problem reoccurred, the apache error log showed:
[Wed Sep 24 16:32:39 2008] [error] [client a.b.c.d] feedback: net::smtp failed to create
object (Invalid argument; Net::SMTP: Bad hostname 'mail.server.hostname')
Now I was starting to get more useful info, as this told me the creation of a new Net::SMTP object
was failing, with an Invalid argument error, and an error message saying
Net::SMTP: Bad hostname 'mail.server.hostname'.
This confirmed that the error was occurring when attempting to execute the following line:
my $smtp = Net::SMTP->new($smtp_server);
Further Investigation
Googling the "Bad hostname" error indicated the SMTP server
could return this error if there was a problem with the hostname of the mail client
(ie, the webserver where this code was running).
To determine if this was the problem, I changed the code to explicitly specify the client domain:
my $smtp = Net::SMTP->new($smtp_server, Hello => 'mail.server.hostname')
or warn "feedback: net::smtp failed to create object ($!; $@)\n";
However, this didn't resolve the problem, and it could still be reproduced approximately once in ten attempts,
so the Hello parameter was removed.
Brainstorming
Other Causes?
I was wondering if the issue could possibly be occurring if the mailserver hostname was failing
to be resolved by DNS.
A quick check on the webserver indicated it was using a single DNS server
(as specified in /etc/resolv.conf). This DNS server was
in the same data centre as the webserver, so there shouldn't be any latency issues
between the webserver and the DNS server.
Testing DNS
Repeatedly attempting a DNS lookup, using the same DNS server that the webserver was using,
of the mailserver hostname being used by Net:SMTP provided some interesting results,
with the DNS lookup occasionally failing with a timeout:
;; connection timed out; no servers could be reached
Note that these tests were performed on the webserver itself, to simulate the DNS query
as closely as possible that would be performed when the Net::SMTP module is attempting
to resolve the mailserver hostname.
The DNS queries were executed using the following syntax:
nslookup mail.server.hostname a.b.c.d
where mail.server.hostname is the hostname of the mailserver
that is to be used for sending email, and a.b.c.d is the IP address
of the DNS server that's being used by the webserver.
Resolution
Summary of Issue
The DNS testing confirms that the Net::SMTP module is occasionally failing to send email
because the webserver was failing to resolve the mailserver hostname, due to
requests to the DNS server timing out.
The Fix
My webhost is only a small company, and the server admins are easy to contact.
I explained the issue to them, and asked them to add some additional DNS servers
into the /etc/resolv.conf on the webserver where this particular site is hosted.
With multiple DNS servers specified, if a query to one server times out, it'll
try the next DNS server, and will repeat until a maximum number of retries have been made.
Conclusion
Since the DNS configuration change on the webserver was made, I have not been able
to reproduce the problem.
It certainly demonstrates that when debugging a software issue, don't rule out the
basics such as DNS!
last updated 2 Dec 2012
|