tiredcoder has asked for the wisdom of the Perl Monks concerning the following question:

I'm having a strange problem with the following simple SMTP script. I am running it on my Win2000 workstation and it is trying to send mail through our Solaris server, which does have SMTP enabled for anonymous access.

The script is:
use strict; use Net::SMTP; my $SMTP_SERVER = "xxx.x.xx.xxx"; my $EMAIL_DOMAIN = "xxx-xx.xxxx.com"; my $mailFrom = "myname\@domain.com"; my $subject = "Test SMTP Message"; my $msg ="This is a test message."; my $mailaddr = $ENV{USER} . "\@" . $EMAIL_DOMAIN; my $smtp = Net::SMTP->new($SMTP_SERVER, Debug => 1); print STDERR "Couldn't connect to smtp server: $!\n" unless $smtp; $smtp->mail($ENV{USER}."\@".$EMAIL_DOMAIN); $smtp->to('me@domain.com'); $smtp->data("\n"); $smtp->datasend("From: $mailFrom\n"); $smtp->datasend("To: me\@domain.com\n"); $smtp->datasend("Subject: $subject\n"); $smtp->datasend($msg); $smtp->dataend(); $smtp->quit;
The debug statements I get back are:
Net::SMTP: Net::SMTP(2.16) Net::SMTP: Net::Cmd(2.19) Net::SMTP: Exporter(5.562) Net::SMTP: IO::Socket::INET(1.25) Net::SMTP: IO::Socket(1.26) Net::SMTP: IO::Handle(1.21) Net::SMTP=GLOB(0x1a72800)<<< 220 ESMTP xxx-xx.xxxx.com Sendmail 8.8. +8+Sun/SMI-S VR4 ready at Fri, 2 Apr 2004 13:12:58 -0500 (EST) Net::SMTP=GLOB(0x1a72800)>>> EHLO MY PC NAME Net::SMTP=GLOB(0x1a72800)<<< 250- xxx-xx.xxxx.com Hello xx.xx.xx.xxx, + pleased to meet you<br> Net::SMTP=GLOB(0x1a72800)<<< 250-EXPN Net::SMTP=GLOB(0x1a72800)<<< 250-VERB Net::SMTP=GLOB(0x1a72800)<<< 250-8BITMIME Net::SMTP=GLOB(0x1a72800)<<< 250-SIZE Net::SMTP=GLOB(0x1a72800)<<< 250-ONEX Net::SMTP=GLOB(0x1a72800)<<< 250-ETRN Net::SMTP=GLOB(0x1a72800)<<< 250-XUSR Net::SMTP=GLOB(0x1a72800)<<< 250 HELP Couldn't connect to smtp server: Bad file descriptor

My research into the 'bad file descriptor' message suggests that I'm getting it because $! has no value since I've already lost the connection to the server. I've talked to our Solaris administrator (since I don't know Unix) and he can't find anything in the SMTP log that even shows I made a connection or encountered any errors on that side. He looked at the data returned by my script and agrees that it does look like I am connecting to the server, then being disconnected for some unknown reason. He tried sending an POP3 email message from my workstation using Outlook and relaying through the Solaris server and it was successful (with no authentication used). We are also able to use telnet on my workstation to send an
smtp message. He doesn't know Perl, but because he is able to send mail through the server anonymously using these other methods, he thinks the fault must lie with the Perl script. This script works fine when I'm using a Windows 2000 server as my smtp server, but the Windows server is not authorized to run SMTP, so I've been told I need to get it working using the Solaris server.

I have tried every variation I can think of in the $smtp->mail(' ') line, since that's the first line sent to the mail server after the connection is established and I thought the problem might lie there. I have also tried adding the Helo and port parameters to the Net::SMTP->new line. I have tried specifying the smtp server name rather than the IP address. No matter what variations I try for the different values and addresses needed (and I've been working on this for 2 days now), I still get the same exact return code.

Does anyone have any suggestions as to what is going on or how I can get some better feedback from the Solaris server?

Thanks,
tiredcoder (really tired)

Edited by BazB fixed formatting, added code and readmore tags.

Replies are listed 'Best First'.
Re: SMTP Connection Problem
by Thelonius (Priest) on Apr 02, 2004 at 19:55 UTC
    My only suggestion is that you scatter this line liberally through your program, Net/Cmd.pm and Net/SMTP.pm to find out the flow:
    print STDERR __FILE__, "(", __LINE__, ")\n";
    That's how I figure out what's going on.
Re: SMTP Connection Problem
by iburrell (Chaplain) on Apr 02, 2004 at 21:38 UTC
    The mail() call is irrelevant since it never gets there. The constructor is failing. It is getting through sending the EHLO command and receiving the response.

    When you did the telnet, did you do exactly what is being sent? I could see the server rejecting the name in the EHLO and dropping the connection. Try setting the Hello parameter in the constructor to the local IP address or hostname.

      I sent the same thing in telnet that I'm trying to send with the Perl. I thought it would be a good way to check that my parameters are ok. Which is why I'm confused on why it works through telnet, but not through the Perl script. I tried setting the Hello parameter to my local IP address and my hostname as you suggested, but I still get the same results. Thanks for the help.
Re: SMTP Connection Problem
by nimdokk (Vicar) on Apr 02, 2004 at 23:44 UTC
    You might also try adding "or die's" into the mix as well. Also, you might try looking at $@ instead of $!, might be more or better information there. Something like:

    my $smtp = Net::SMTP->new($SMTP_SERVER, Debug => 1) or die "Cannot con +nect to $SMTP_SEVER. $@";

    That should at least tell you if you are making the connection in the first place.


    "Ex Libris un Peut de Tout"
      When I use the "or die" line you suggested, I still get the identical return code that I posted, followed by the "cannot connect to xxx.xx.xxx.xxx. at c:\Email.pl line 37." So the $@ didn't give me any useful information,either. I appreciate the suggestion, though!
Re: SMTP Connection Problem
by tachyon (Chancellor) on Apr 03, 2004 at 01:27 UTC

    Before I discovered the full power of CPAN I used to do raw socket stuff to talk to servers. This code is in now way recommeneded for any sort of prodution use but is short and should allow you to diagnose the issue quickly as it lets you watch a SMTP transaction. You will need remove the CGI param() args. If this works then you have isolated it as a specific Net::SMTP problem.

    sub smtp_relay { my $ip = $q->param('ip') || 'localhost'; my $port = $q->param('port') || 25; my $timeout = $q->param('timeout') || 30; my $domain = $q->param('domain') ||'localhost'; my $to = $q->param('to') ||'you@yourdomain.com'; my $from = $q->param('from') ||'nobody@nowhere.com'; my $server = get_host_by_addr($ip); $ip = get_host_by_name($ip); my $message= "Test relay message for $server [$ip]. You will get this message only if $server is an OPEN RELAY \015\01 +2.\015\012 "; print "Attempting to connect to SMTP $server [$ip] on port $port\n +"; my $sock = IO::Socket::INET->new( PeerAddr => $ip, PeerPort => $port, Proto => 'tcp', Timeout => $timeout ); do{ print $CONN_FAILURE; return} unless $sock; $sock->autoflush(1); my $data = getline($sock); sendline( $sock, "HELO $domain" ); $data = getline($sock); sendline( $sock,"MAIL from: <$from>" ); $data = getline($sock); sendline( $sock, "RCPT to: <$to>" ); $data = getline($sock); if ($data =~ m/^550/ ) { sendline( $sock, 'QUIT' ); print "</pre><h3>$server [$ip] $NOT_RELAY_SERVER</h3>"; return $NOT_RELAY_SERVER; } sendline( $sock, 'DATA' ); $data = getline($sock); sendline( $sock, $message ); $data = getline($sock); sendline( $sock, 'QUIT' ); if ( $data =~ /^250.*(?:message accepted)|(?:queued mail for deliv +ery)/i ) { print "</pre><h3>$server [$ip] $IS_RELAY_SERVER</h3>"; return $IS_RELAY_SERVER; } else { print "</pre><h3>$server [$ip] $POSSIBLE_RELAY</h3>"; return $POSSIBLE_RELAY } sub sendline { my ( $sock, $line ) = @_; $sock->write($line."\015\012"); print $line . "\n"; } sub getline { my $sock = shift; my $data = ''; while ( defined( sysread($sock, my $buffer,1) ) ) { $data .= $buffer; last if $buffer eq "\n"; } print $data; return $data; } }

    cheers

    tachyon