I am using Strawberry Perl (v5.16.3) on a Windows 2008 server. I have added some CPAN modules for use in a script, but this seems to have broken MIME:Lite (which is used by other scripts on this box). When I run the following code:
use strict;
use warnings;
use v5.16;
use MIME::Lite;
my $msg = MIME::Lite->new(From => 'person@domain.com',
To => 'person@domain.com',
Subject => "testing",
Type => 'multipart/mixed');
my $dataString = "Trying to figure out why this isn't working.\r\n";
$msg->attach( Type => 'TEXT',
Data => $dataString);
$msg->send('smtp', 'mailhost.com', Debug=>1);
I get the following error message:
MIME::Lite::SMTP>>> MIME::Lite::SMTP
MIME::Lite::SMTP>>> Net::SMTP(3.10)
MIME::Lite::SMTP>>> Net::Cmd(3.10)
MIME::Lite::SMTP>>> Exporter(5.67)
MIME::Lite::SMTP>>> IO::Socket::INET6(2.69)
MIME::Lite::SMTP>>> IO::Socket(1.34)
MIME::Lite::SMTP>>> IO::Handle(1.33)
MIME::Lite::SMTP: Net::Cmd::_is_closed(): unexpected EOF on command channel: at d:/strawberry/perl/site/lib/MIME/Lite.pm line 2877.
SMTP Failed to connect to mail server: Bad file descriptor.
The modules I installed where Email::Simple, Email::Sender, Email::MIME::CreateHTML & String::Util. As I am sure you know, there were various dependencies that were installed as well.
I would just switch the scripts over to Email::Sender but that is getting a 421 error from the server (which is yet another mystery). I am able to connect to the mail server through telnet and get a 'HELO' with no problem.
I fear the Perl installation is now all jacked up but I am hoping one of you brilliant guys might have some insight on how to fix it.
Thanks in advance for your help.
EDIT: I noticed that the Socket.pm in perl/lib was updated. Could that be causing the problem? I updated MIME::Lite to the latest (ver. 3.030) but that did not solve the problem.
EDIT #2: Per, ikegami's reply, added print statements to NET::SMTP:
sub new {
print "inside Net::SMTP::new\n";
my $self = shift;
my $type = ref($self) || $self;
my ($host, %arg);
if (@_ % 2) {
$host = shift;
%arg = @_;
}
else {
%arg = @_;
$host = delete $arg{Host};
}
print "checked for SSL.\n";
if ($arg{SSL}) {
# SSL from start
die $nossl_warn if !$ssl_class;
$arg{Port} ||= 465;
}
my $hosts = defined $host ? $host : $NetConfig{smtp_hosts};
my $obj;
$arg{Timeout} = 120 if ! defined $arg{Timeout};
print "set timeout: $arg{Timeout}. \n";
foreach my $h (@{ref($hosts) ? $hosts : [$hosts]}) {
print "host: $h, port: $arg{Port}, laddr: $arg{LocalAddr}, lport: $arg{LocalPort}, familyKey: " . ( $arg{Domain} || $arg{Family} ) . "\n";
$obj = $type->SUPER::new(
PeerAddr => ($host = $h),
PeerPort => $arg{Port} || 'smtp(25)',
LocalAddr => $arg{LocalAddr},
LocalPort => $arg{LocalPort},
$family_key => $arg{Domain} || $arg{Family},
Proto => 'tcp',
Timeout => $arg{Timeout}
)
and last;
}
print "$obj\n";
return
unless defined $obj;
print "object defined. \n";
${*$obj}{'net_smtp_arg'} = \%arg;
${*$obj}{'net_smtp_host'} = $host;
print "set net_smtp_host to $host\n";
if ($arg{SSL}) {
print "setting SSL. \n";
Net::SMTP::_SSL->start_SSL($obj,%arg)
or return;
}
$obj->autoflush(1);
print "set autoflush.\n";
$obj->debug(exists $arg{Debug} ? $arg{Debug} : undef);
print "setting debug: $arg{Debug}\n";
my $response = $obj->response();
print "object response: $response (5 == CMD_ERROR)\n";
unless ($obj->response() == CMD_OK) {
my $err = ref($obj) . ": " . $obj->code . " " . $obj->message;
$obj->close();
$@ = $err;
print "returning because response was not CMD_OK\n";
return;
} ....
Here's the output:
D:\strawberry>perl D:\Perl\Src\pmTasks\emailTest.pl
inside Net::SMTP::new
checked for SSL.
set timeout: 120.
Use of uninitialized value in concatenation (.) or string at D:/strawberry/perl/lib/Net/SMTP.pm line 83, <DATA> line 100
3.
Use of uninitialized value in concatenation (.) or string at D:/strawberry/perl/lib/Net/SMTP.pm line 83, <DATA> line 100
3.
Use of uninitialized value in concatenation (.) or string at D:/strawberry/perl/lib/Net/SMTP.pm line 83, <DATA> line 100
3.
Use of uninitialized value in concatenation (.) or string at D:/strawberry/perl/lib/Net/SMTP.pm line 83, <DATA> line 100
3.
host: {correct_mailhost_here}, port: , laddr: , lport: , familyKey:
MIME::Lite::SMTP=GLOB(0x1f36fbc)
object defined.
set net_smtp_host to {correct_mailhost_here}
set autoflush.
MIME::Lite::SMTP>>> MIME::Lite::SMTP
MIME::Lite::SMTP>>> Net::SMTP(3.10)
MIME::Lite::SMTP>>> Net::Cmd(3.10)
MIME::Lite::SMTP>>> Exporter(5.67)
MIME::Lite::SMTP>>> IO::Socket::INET6(2.69)
MIME::Lite::SMTP>>> IO::Socket(1.34)
MIME::Lite::SMTP>>> IO::Handle(1.33)
setting debug: 1
MIME::Lite::SMTP: Net::Cmd::_is_closed(): unexpected EOF on command channel: at D:/strawberry/perl/site/lib/MIME/Lite.pm line 2877.
object response: 5 (5 == CMD_ERROR)
MIME::Lite::SMTP: Net::Cmd::_is_closed(): unexpected EOF on command channel: at D:/strawberry/perl/site/lib/MIME/Lite.pm line 2877.
returning because response was not CMD_OK
SMTP Failed to connect to mail server: Bad file descriptor
So, it seems that reason it is returning is that the $obj
has a response of CMD_ERROR
. The only parameter it is sending to the $obj=$type->SUPER::new
is the host. (which is the correct host, but I had to blank it out above).
So, I'm not sure which superclass this is calling. It seems to be returning the constants from NET::Cmd, but there is no new
subroutine. IO::Socket:INET calls the new from IO::Socket, which calls the new from IO::Handle which seems to be calling the fdopen C code? I get a little lost here. However, thanks for your help so far. Seems that we are almost getting to the root of the problem here.
With Net::SMTP version 3.x support for SSL and IPv6 was added. If the necessary packages are installed (i.e. IO::Socket::IP or IO::Socket::INET6) it will use getaddrinfo to resolve the name which usually prefers IPv6 before IPv4.
This is not a problem if everything is properly setup. But in your case the hostname of the mail server resolves to both IPv6 and IPv4 address even though there is no mail server listening on the IPv6 address or a firewall is blocking the connection. Thus results in a failed connection because getaddrinfo returns that IPv6 should be used but the server is not reachable by IPv6.
The proper fix would be to either remove the IPv6 record for the host or to make it accessible by IPv6. As long as this is not the case one might work around the problem by explicitly enforcing IPv4 in Net::SMTP:
use Socket;
Net::SMTP->new(host, Domain => AF_INET,...);