diff --git a/lib/Email/Sender/Transport/SMTP.pm b/lib/Email/Sender/Transport/SMTP.pm index 35a162b..79640bb 100644 --- a/lib/Email/Sender/Transport/SMTP.pm +++ b/lib/Email/Sender/Transport/SMTP.pm @@ -27,7 +27,9 @@ The following attributes may be passed to the constructor: =over 4 -=item C: the name of the host to connect to; defaults to C +=item C: the DNS name, IPv4 or IPv6 address of the host to connect to; + defaults to C. Do not include a port number. Use the C + option instead. =item C: if 'starttls', use STARTTLS; if 'ssl' (or 1), connect securely; otherwise, no security @@ -45,8 +47,10 @@ IO::Socket::SSL sub BUILD { my ($self) = @_; - Carp::croak("do not pass port number to SMTP transport in host, use port parameter") - if $self->host =~ /:/; + Carp::croak("Do not pass port number to SMTP transport in host, use port parameter") + if $self->host =~ /^\d+\.\d+\.\d+\.\d+:/ # IPv4 address + or $self->host =~ /^\[[\w:]{3,}\]:/ # IPv6 address + or $self->host =~ /^[\w\.]{3,}:/; # DNS name } has host => (is => 'ro', isa => Str, default => sub { 'localhost' }); diff --git a/t/smtp-via-mock.t b/t/smtp-via-mock.t index c546cf6..2968214 100644 --- a/t/smtp-via-mock.t +++ b/t/smtp-via-mock.t @@ -2,6 +2,7 @@ use strict; use warnings; use Test::More; +use Test::Exception; BEGIN { plan skip_all => 'Test::MockObject required to test SMTP transport by mocking' @@ -32,7 +33,7 @@ BEGIN { $mock_smtp->{failaddr}{'permfail@example.net'} = [ 519 => 'Permanent STHU' ]; } -plan tests => 95; +plan tests => 96; use Email::Sender::Transport::SMTP; use Email::Sender::Transport::SMTP::Persistent; @@ -368,3 +369,45 @@ subtest "quoteaddr" => sub { is($q->(qq{$local\@example.com}), $want, "correct behavior for $local"); } }; + +subtest "portinaddr" => sub { + my @lives_tests = ( + '1.1.1.1', 'IPv4 address', + '1::', 'IPv6 address 1 groups', + '1::8', 'IPv6 address 2 groups', + '1::ae:8', 'IPv6 address 3 groups', + '1::f45a:7:8', 'IPv6 address 4 groups', + '1::5:bd23:7:8', 'IPv6 address 5 groups', + '1::26fa:5:6:7:8', 'IPv6 address 6 groups', + '1::3:4:5:66ff:7:8', 'IPv6 address 7 groups', + '1:2:3:4:098a:6:7:8', 'IPv6 address 8 groups', + 'server', 'Unqualified DNS name', + 'corp.com', 'DNS zone', + 'server.corp.com', 'Fully-qualified DNS name', + ); + my @dies_tests = ( + '1.1.1.1:125', 'IPv4 address with port', + '[::1]:125', 'IPv6 address shortest form with port', + '[1::]:125', 'IPv6 address 1 groups]:125', + '[1::8]:125', 'IPv6 address 2 groups]:125', + '[1::ae:8]:125', 'IPv6 address 3 groups]:125', + '[1::f45a:7:8]:125', 'IPv6 address 4 groups]:125', + '[1::5:bd23:7:8]:125', 'IPv6 address 5 groups]:125', + '[1::26fa:5:6:7:8]:125', 'IPv6 address 6 groups]:125', + '[1::3:4:5:66ff:7:8]:125', 'IPv6 address 7 groups]:125', + '[1:2:3:4:098a:6:7:8]:125', 'IPv6 address 8 groups]:125', + 'server:125', 'Unqualified DNS name with port', + 'corp.com:125', 'DNS zone with port', + 'server.corp.com:125', 'Fully-qualified DNS name with port', + ); + + plan tests => (scalar(@lives_tests) + scalar(@dies_tests))/2; + + while (my ($host, $test_name) = splice @lives_tests, 0, 2) { + lives_ok(sub {Email::Sender::Transport::SMTP->new({ host => $host })}, $test_name); + } + + while (my ($host, $test_name) = splice @dies_tests, 0, 2) { + dies_ok(sub {Email::Sender::Transport::SMTP->new({ host => $host })}, $test_name); + } +};