diff options
Diffstat (limited to 'Net/SMTP.pm')
-rw-r--r-- | Net/SMTP.pm | 108 |
1 files changed, 100 insertions, 8 deletions
diff --git a/Net/SMTP.pm b/Net/SMTP.pm index 3d193a4..819ce8c 100644 --- a/Net/SMTP.pm +++ b/Net/SMTP.pm @@ -16,9 +16,33 @@ use IO::Socket; use Net::Cmd; use Net::Config; -$VERSION = "2.34"; +$VERSION = "2.35"; + +# Code for detecting if we can use SSL +my $ssl_class = eval { + require IO::Socket::SSL; + # first version with default CA on most platforms + IO::Socket::SSL->VERSION(1.968); +} && 'IO::Socket::SSL'; +my $nossl_warn = !$ssl_class && + 'To use SSL please install IO::Socket::SSL with version>=1.968'; + +# Code for detecting if we can use IPv6 +my $inet6_class = + eval { + require IO::Socket::IP; + IO::Socket::IP->VERSION(0.20); + } && 'IO::Socket::IP' || + eval { + require IO::Socket::INET6; + IO::Socket::INET6->VERSION(2.62); + } && 'IO::Socket::INET6'; + +sub can_ssl { $ssl_class }; +sub can_inet6 { $inet6_class }; -@ISA = qw(Net::Cmd IO::Socket::INET); + +@ISA = ( 'Net::Cmd', $inet6_class || 'IO::Socket::INET' ); sub new { @@ -33,9 +57,18 @@ sub new { %arg = @_; $host = delete $arg{Host}; } + + 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}; + my $h; foreach $h (@{ref($hosts) ? $hosts : [$hosts]}) { $obj = $type->SUPER::new( @@ -44,9 +77,7 @@ sub new { LocalAddr => $arg{LocalAddr}, LocalPort => $arg{LocalPort}, Proto => 'tcp', - Timeout => defined $arg{Timeout} - ? $arg{Timeout} - : 120 + Timeout => $arg{Timeout} ) and last; } @@ -54,6 +85,12 @@ sub new { return undef unless defined $obj; + ${*$obj}{'net_smtp_arg'} = \%arg; + if ($arg{SSL}) { + Net::SMTP::_SSLified->start_SSL($obj,SSL_verifycn_name => $host,%arg) + or return; + } + $obj->autoflush(1); $obj->debug(exists $arg{Debug} ? $arg{Debug} : undef); @@ -189,11 +226,25 @@ sub hello { } return undef unless $ok; + ${*$me}{net_smtp_hello_domain} = $domain; $msg[0] =~ /\A\s*(\S+)/; return ($1 || " "); } +sub starttls { + my $self = shift; + $ssl_class or die $nossl_warn; + $self->_STARTTLS or return; + Net::SMTP::_SSLified->start_SSL($self, + %{ ${*$self}{'net_smtp_arg'} }, # (ssl) args given in new + @_ # more (ssl) args + ) or return; + + # another hello after starttls to read new ESMTP capabilities + return $self->hello(${*$self}{net_smtp_hello_domain}); +} + sub supports { my $self = shift; @@ -531,6 +582,26 @@ sub _BDAT { shift->command("BDAT", @_) } sub _TURN { shift->unsupported(@_); } sub _ETRN { shift->command("ETRN", @_)->response() == CMD_OK } sub _AUTH { shift->command("AUTH", @_)->response() == CMD_OK } +sub _STARTTLS { shift->command("STARTTLS")->response() == CMD_OK } + + +{ + package Net::SMTP::_SSLified; + our @ISA = ( $ssl_class ? ($ssl_class):(), 'Net::SMTP' ); + sub starttls { die "SMTP connection is already in SSL mode" } + sub start_SSL { + my ($class,$smtp,%arg) = @_; + delete @arg{ grep { !m{^SSL_} } keys %arg }; + ( $arg{SSL_verifycn_name} ||= $smtp->host ) + =~s{(?<!:):[\w()]+$}{}; # strip port + $arg{SSL_verifycn_scheme} ||= 'smtp'; + my $ok = $class->SUPER::start_SSL($smtp,%arg); + $@ = $ssl_class->errstr if !$ok; + return $ok; + } +} + + 1; @@ -621,9 +692,15 @@ B<Host> - SMTP host to connect to. It may be a single scalar (hostname[:port]), as defined for the C<PeerAddr> option in L<IO::Socket::INET>, or a reference to an array with hosts to try in turn. The L</host> method will return the value which was used to connect to the host. +Format - C<PeerHost> from L<IO::Socket::INET> new method. -B<Port> - port to connect to. Format - C<PeerHost> from L<IO::Socket::INET> new method. -Default - 25. +B<Port> - port to connect to. +Default - 25 for plain SMTP and 465 for immediate SSL. + +B<SSL> - If the connection should be done from start with SSL, contrary to later +upgrade with C<starttls>. +You can use SSL arguments as documented in L<IO::Socket::SSL>, but it will +usually use the right arguments already. B<LocalAddr> and B<LocalPort> - These parameters are passed directly to IO::Socket to allow binding the socket to a local port. @@ -655,6 +732,14 @@ Example: Debug => 1, ); + # the same with direct SSL + $smtp = Net::SMTP->new('mailhost', + Hello => 'my.mail.domain', + Timeout => 30, + Debug => 1, + SSL => 1, + ); + # Connect to the default server from Net::config $smtp = Net::SMTP->new( Hello => 'my.mail.domain', @@ -702,6 +787,12 @@ to connect to the host. Request a queue run for the DOMAIN given. +=item starttls ( SSLARGS ) + +Upgrade existing plain connection to SSL. +You can use SSL arguments as documented in L<IO::Socket::SSL>, but it will +usually use the right arguments already. + =item auth ( USERNAME, PASSWORD ) Attempt SASL authentication. Requires Authen::SASL module. @@ -868,7 +959,8 @@ accept the address surrounded by angle brackets. =head1 SEE ALSO -L<Net::Cmd> +L<Net::Cmd>, +L<IO::Socket::SSL> =head1 AUTHOR |