包升级后,MIME :: Lite在命令通道错误上抛出意外的EOF

时间:2016-12-05 22:31:51

标签: perl email module smtp mime

我在Windows 2008服务器上使用Strawberry Perl(v5.16.3)。我添加了一些用于脚本的CPAN模块,但这似乎破坏了MIME:Lite(此框中的其他脚本使用它)。当我运行以下代码时:

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);

我收到以下错误消息:

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.

我安装的模块,其中Email :: Simple,Email :: Sender,Email :: MIME :: CreateHTML&字符串::的Util。我相信你知道,也安装了各种依赖项。

我只是将脚本切换到Email :: Sender,但是从服务器获得了421错误(这是另一个谜)。我能够通过telnet连接到邮件服务器并获得“HELO”没有问题。

我担心Perl的安装现在全都搞砸了,但我希望你们中的一个能够对如何修复它们有所了解。

提前感谢您的帮助。

编辑:我注意到perl / lib中的Socket.pm已更新。这会导致问题吗?我将MIME :: Lite更新为最新版本(版本3.030),但没有解决问题。

编辑#2:Per,ikegami的回复,在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;
  } ....

这是输出:

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

因此,它返回的原因似乎是$obj的响应为CMD_ERROR。它发送给$obj=$type->SUPER::new的唯一参数是主机。 (这是正确的主机,但我不得不在上面将其删空)。

所以,我不确定这个叫哪个超类。它似乎从NET :: Cmd返回常量,但没有new子例程。 IO :: Socket:INET从IO :: Socket调用new,它从IO :: Handle调用new,它似乎调用了fdopen C代码?我在这里迷失了一点。但是,感谢你的帮助到目前为止。似乎我们在这里几乎找到问题的根源。

1 个答案:

答案 0 :(得分:1)

使用Net :: SMTP版本3.x添加了对SSL和IPv6的支持。如果安装了必要的软件包(即IO :: Socket :: IP或IO :: Socket :: INET6),它将使用getaddrinfo来解析通常在IPv4之前优先使用IPv6的名称。

如果一切设置正确,这不是问题。但在您的情况下,即使没有邮件服务器侦听IPv6地址或防火墙阻止连接,邮件服务器的主机名也会解析为IPv6和IPv4地址。因此导致连接失败,因为getaddrinfo返回应该使用IPv6,但IPv6无法访问服务器。

正确的解决方法是删除主机的IPv6记录或使其可由IPv6访问。只要不是这种情况,可以通过在Net :: SMTP中明确强制执行IPv4来解决问题:

 use Socket;
 Net::SMTP->new(host, Domain => AF_INET,...);