File Coverage

blib/lib/Net/SMTP.pm
Criterion Covered Total %
statement 108 318 33.9
branch 24 180 13.3
condition 13 64 20.3
subroutine 22 60 36.6
pod 23 25 92.0
total 190 647 29.3


line stmt bran cond sub pod time code
1             # Net::SMTP.pm
2             #
3             # Copyright (C) 1995-2004 Graham Barr. All rights reserved.
4             # Copyright (C) 2013-2016, 2020 Steve Hay. All rights reserved.
5             # This module is free software; you can redistribute it and/or modify it under
6             # the same terms as Perl itself, i.e. under the terms of either the GNU General
7             # Public License or the Artistic License, as specified in the F file.
8              
9             package Net::SMTP;
10              
11 6     6   305216 use 5.008001;
  6         51  
12              
13 6     6   26 use strict;
  6         9  
  6         97  
14 6     6   21 use warnings;
  6         11  
  6         147  
15              
16 6     6   26 use Carp;
  6         8  
  6         268  
17 6     6   2083 use IO::Socket;
  6         43094  
  6         24  
18 6     6   4262 use Net::Cmd;
  6         12  
  6         292  
19 6     6   1385 use Net::Config;
  6         12  
  6         448  
20 6     6   36 use Socket;
  6         11  
  6         3263  
21              
22             our $VERSION = "3.14";
23              
24             # Code for detecting if we can use SSL
25             my $ssl_class = eval {
26             require IO::Socket::SSL;
27             # first version with default CA on most platforms
28 6     6   35 no warnings 'numeric';
  6         10  
  6         526  
29             IO::Socket::SSL->VERSION(2.007);
30             } && 'IO::Socket::SSL';
31              
32             my $nossl_warn = !$ssl_class &&
33             'To use SSL please install IO::Socket::SSL with version>=2.007';
34              
35             # Code for detecting if we can use IPv6
36             my $family_key = 'Domain';
37             my $inet6_class = eval {
38             require IO::Socket::IP;
39 6     6   32 no warnings 'numeric';
  6         11  
  6         377  
40             IO::Socket::IP->VERSION(0.25) || die;
41             $family_key = 'Family';
42             } && 'IO::Socket::IP' || eval {
43             require IO::Socket::INET6;
44 6     6   32 no warnings 'numeric';
  6         8  
  6         14393  
45             IO::Socket::INET6->VERSION(2.62);
46             } && 'IO::Socket::INET6';
47              
48 3     3 1 285 sub can_ssl { $ssl_class };
49 1     1 1 97 sub can_inet6 { $inet6_class };
50              
51             our @ISA = ('Net::Cmd', $inet6_class || 'IO::Socket::INET');
52              
53             sub new {
54 3     3 1 693327 my $self = shift;
55 3   33     226 my $type = ref($self) || $self;
56 3         51 my ($host, %arg);
57 3 50       78 if (@_ % 2) {
58 3         55 $host = shift;
59 3         125 %arg = @_;
60             }
61             else {
62 0         0 %arg = @_;
63 0         0 $host = delete $arg{Host};
64             }
65              
66 3 100       65 if ($arg{SSL}) {
67             # SSL from start
68 2 50       28 die $nossl_warn if !$ssl_class;
69 2   50     276 $arg{Port} ||= 465;
70             }
71              
72 3 50       31 my $hosts = defined $host ? $host : $NetConfig{smtp_hosts};
73 3         8 my $obj;
74              
75 3 50       58 $arg{Timeout} = 120 if ! defined $arg{Timeout};
76              
77 3 50       6 foreach my $h (@{ref($hosts) ? $hosts : [$hosts]}) {
  3         32  
78             $obj = $type->SUPER::new(
79             PeerAddr => ($host = $h),
80             PeerPort => $arg{Port} || 'smtp(25)',
81             LocalAddr => $arg{LocalAddr},
82             LocalPort => $arg{LocalPort},
83             $family_key => $arg{Domain} || $arg{Family},
84             Proto => 'tcp',
85             Timeout => $arg{Timeout}
86             )
87 3 50 100     476 and last;
      33        
88             }
89              
90             return
91 3 50       5173 unless defined $obj;
92              
93 3         6 ${*$obj}{'net_smtp_arg'} = \%arg;
  3         23  
94 3         5 ${*$obj}{'net_smtp_host'} = $host;
  3         8  
95              
96 3 100       16 if ($arg{SSL}) {
97 2 50       78 Net::SMTP::_SSL->start_SSL($obj,%arg)
98             or return;
99             }
100              
101 3         48 $obj->autoflush(1);
102              
103 3 50       299 $obj->debug(exists $arg{Debug} ? $arg{Debug} : undef);
104              
105 3 50       101 unless ($obj->response() == CMD_OK) {
106 0         0 my $err = ref($obj) . ": " . $obj->code . " " . $obj->message;
107 0         0 $obj->close();
108 0         0 $@ = $err;
109 0         0 return;
110             }
111              
112 3         6 ${*$obj}{'net_smtp_exact_addr'} = $arg{ExactAddresses};
  3         6  
113              
114 3         63 (${*$obj}{'net_smtp_banner'}) = $obj->message;
  3         7  
115 3         9 (${*$obj}{'net_smtp_domain'}) = $obj->message =~ /\A\s*(\S+)/;
  3         12  
116              
117 3 50 33     11 if (!exists $arg{SendHello} || $arg{SendHello}) {
118 3 50 50     95 unless ($obj->hello($arg{Hello} || "")) {
119 0         0 my $err = ref($obj) . ": " . $obj->code . " " . $obj->message;
120 0         0 $obj->close();
121 0         0 $@ = $err;
122 0         0 return;
123             }
124             }
125              
126 3         15 $obj;
127             }
128              
129              
130             sub host {
131 0     0 1 0 my $me = shift;
132 0         0 ${*$me}{'net_smtp_host'};
  0         0  
133             }
134              
135             ##
136             ## User interface methods
137             ##
138              
139              
140             sub banner {
141 0     0 1 0 my $me = shift;
142              
143 0   0     0 return ${*$me}{'net_smtp_banner'} || undef;
144             }
145              
146              
147             sub domain {
148 0     0 1 0 my $me = shift;
149              
150 0   0     0 return ${*$me}{'net_smtp_domain'} || undef;
151             }
152              
153              
154             sub etrn {
155 0     0 1 0 my $self = shift;
156 0 0       0 defined($self->supports('ETRN', 500, ["Command unknown: 'ETRN'"]))
157             && $self->_ETRN(@_);
158             }
159              
160              
161             sub auth {
162 0     0 1 0 my ($self, $username, $password) = @_;
163              
164 0 0       0 eval {
165 0         0 require MIME::Base64;
166 0         0 require Authen::SASL;
167             } or $self->set_status(500, ["Need MIME::Base64 and Authen::SASL todo auth"]), return 0;
168              
169 0         0 my $mechanisms = $self->supports('AUTH', 500, ["Command unknown: 'AUTH'"]);
170 0 0       0 return unless defined $mechanisms;
171              
172 0         0 my $sasl;
173              
174 0 0 0     0 if (ref($username) and UNIVERSAL::isa($username, 'Authen::SASL')) {
175 0         0 $sasl = $username;
176 0         0 my $requested_mechanisms = $sasl->mechanism();
177 0 0 0     0 if (! defined($requested_mechanisms) || $requested_mechanisms eq '') {
178 0         0 $sasl->mechanism($mechanisms);
179             }
180             }
181             else {
182 0 0       0 die "auth(username, password)" if not length $username;
183 0         0 $sasl = Authen::SASL->new(
184             mechanism => $mechanisms,
185             callback => {
186             user => $username,
187             pass => $password,
188             authname => $username,
189             },
190             debug => $self->debug
191             );
192             }
193              
194 0         0 my $client;
195             my $str;
196 0         0 do {
197 0 0       0 if ($client) {
198             # $client mechanism failed, so we need to exclude this mechanism from list
199 0         0 my $failed_mechanism = $client->mechanism;
200 0 0       0 return unless defined $failed_mechanism;
201 0 0       0 $self->debug_text("Auth mechanism failed: $failed_mechanism")
202             if $self->debug;
203 0         0 $mechanisms =~ s/\b\Q$failed_mechanism\E\b//;
204 0 0       0 return unless $mechanisms =~ /\S/;
205 0         0 $sasl->mechanism($mechanisms);
206             }
207            
208             # We should probably allow the user to pass the host, but I don't
209             # currently know and SASL mechanisms that are used by smtp that need it
210              
211 0         0 $client = $sasl->client_new('smtp', ${*$self}{'net_smtp_host'}, 0);
  0         0  
212 0         0 $str = $client->client_start;
213             } while (!defined $str);
214              
215             # We don't support sasl mechanisms that encrypt the socket traffic.
216             # todo that we would really need to change the ISA hierarchy
217             # so we don't inherit from IO::Socket, but instead hold it in an attribute
218              
219 0         0 my @cmd = ("AUTH", $client->mechanism);
220 0         0 my $code;
221              
222 0 0 0     0 push @cmd, MIME::Base64::encode_base64($str, '')
223             if defined $str and length $str;
224              
225 0         0 while (($code = $self->command(@cmd)->response()) == CMD_MORE) {
226 0         0 my $str2 = MIME::Base64::decode_base64(($self->message)[0]);
227 0 0       0 $self->debug_print(0, "(decoded) " . $str2 . "\n") if $self->debug;
228              
229 0         0 $str = $client->client_step($str2);
230 0         0 @cmd = (
231             MIME::Base64::encode_base64($str, '')
232             );
233              
234 0 0       0 $self->debug_print(1, "(decoded) " . $str . "\n") if $self->debug;
235             }
236              
237 0         0 $code == CMD_OK;
238             }
239              
240              
241             sub hello {
242 4     4 1 18 my $me = shift;
243 4   100     51 my $domain = shift || "localhost.localdomain";
244 4         46 my $ok = $me->_EHLO($domain);
245 4         16 my @msg = $me->message;
246              
247 4 50       14 if ($ok) {
    0          
248 4         30 my $h = ${*$me}{'net_smtp_esmtp'} = {};
  4         51  
249 4         34 foreach my $ln (@msg) {
250 9 50       105 $h->{uc $1} = $2
251             if $ln =~ /([-\w]+)\b[= \t]*([^\n]*)/;
252             }
253             }
254             elsif ($me->status == CMD_ERROR) {
255 0 0       0 @msg = $me->message
256             if $ok = $me->_HELO($domain);
257             }
258              
259 4 50       14 return unless $ok;
260 4         28 ${*$me}{net_smtp_hello_domain} = $domain;
  4         18  
261              
262 4         30 $msg[0] =~ /\A\s*(\S+)/;
263 4   50     38 return ($1 || " ");
264             }
265              
266             sub starttls {
267 1     1 1 1801 my $self = shift;
268 1 50       4 $ssl_class or die $nossl_warn;
269 1 50       20 $self->_STARTTLS or return;
270             Net::SMTP::_SSL->start_SSL($self,
271 1 50       3 %{ ${*$self}{'net_smtp_arg'} }, # (ssl) args given in new
  1         1  
  1         26  
272             @_ # more (ssl) args
273             ) or return;
274              
275             # another hello after starttls to read new ESMTP capabilities
276 1         3 return $self->hello(${*$self}{net_smtp_hello_domain});
  1         6  
277             }
278              
279              
280             sub supports {
281 0     0 0 0 my $self = shift;
282 0         0 my $cmd = uc shift;
283 0         0 return ${*$self}{'net_smtp_esmtp'}->{$cmd}
284 0 0       0 if exists ${*$self}{'net_smtp_esmtp'}->{$cmd};
  0         0  
285 0 0       0 $self->set_status(@_)
286             if @_;
287 0         0 return;
288             }
289              
290              
291             sub _addr {
292 0     0   0 my $self = shift;
293 0         0 my $addr = shift;
294 0 0       0 $addr = "" unless defined $addr;
295              
296 0 0       0 if (${*$self}{'net_smtp_exact_addr'}) {
  0         0  
297 0 0       0 return $1 if $addr =~ /^\s*(<.*>)\s*$/s;
298             }
299             else {
300 0 0       0 return $1 if $addr =~ /(<[^>]*>)/;
301 0         0 $addr =~ s/^\s+|\s+$//sg;
302             }
303              
304 0         0 "<$addr>";
305             }
306              
307              
308             sub mail {
309 0     0 1 0 my $me = shift;
310 0         0 my $addr = _addr($me, shift);
311 0         0 my $opts = "";
312              
313 0 0       0 if (@_) {
314 0         0 my %opt = @_;
315 0         0 my ($k, $v);
316              
317 0 0       0 if (exists ${*$me}{'net_smtp_esmtp'}) {
  0         0  
318 0         0 my $esmtp = ${*$me}{'net_smtp_esmtp'};
  0         0  
319              
320 0 0       0 if (defined($v = delete $opt{Size})) {
321 0 0       0 if (exists $esmtp->{SIZE}) {
322 0         0 $opts .= sprintf " SIZE=%d", $v + 0;
323             }
324             else {
325 0         0 carp 'Net::SMTP::mail: SIZE option not supported by host';
326             }
327             }
328              
329 0 0       0 if (defined($v = delete $opt{Return})) {
330 0 0       0 if (exists $esmtp->{DSN}) {
331 0 0       0 $opts .= " RET=" . ((uc($v) eq "FULL") ? "FULL" : "HDRS");
332             }
333             else {
334 0         0 carp 'Net::SMTP::mail: DSN option not supported by host';
335             }
336             }
337              
338 0 0       0 if (defined($v = delete $opt{Bits})) {
339 0 0 0     0 if ($v eq "8") {
    0          
    0          
340 0 0       0 if (exists $esmtp->{'8BITMIME'}) {
341 0         0 $opts .= " BODY=8BITMIME";
342             }
343             else {
344 0         0 carp 'Net::SMTP::mail: 8BITMIME option not supported by host';
345             }
346             }
347             elsif ($v eq "binary") {
348 0 0 0     0 if (exists $esmtp->{'BINARYMIME'} && exists $esmtp->{'CHUNKING'}) {
349 0         0 $opts .= " BODY=BINARYMIME";
350 0         0 ${*$me}{'net_smtp_chunking'} = 1;
  0         0  
351             }
352             else {
353 0         0 carp 'Net::SMTP::mail: BINARYMIME option not supported by host';
354             }
355             }
356             elsif (exists $esmtp->{'8BITMIME'} or exists $esmtp->{'BINARYMIME'}) {
357 0         0 $opts .= " BODY=7BIT";
358             }
359             else {
360 0         0 carp 'Net::SMTP::mail: 8BITMIME and BINARYMIME options not supported by host';
361             }
362             }
363              
364 0 0       0 if (defined($v = delete $opt{Transaction})) {
365 0 0       0 if (exists $esmtp->{CHECKPOINT}) {
366 0         0 $opts .= " TRANSID=" . _addr($me, $v);
367             }
368             else {
369 0         0 carp 'Net::SMTP::mail: CHECKPOINT option not supported by host';
370             }
371             }
372              
373 0 0       0 if (defined($v = delete $opt{Envelope})) {
374 0 0       0 if (exists $esmtp->{DSN}) {
375 0         0 $v =~ s/([^\041-\176]|=|\+)/sprintf "+%02X", ord($1)/sge;
  0         0  
376 0         0 $opts .= " ENVID=$v";
377             }
378             else {
379 0         0 carp 'Net::SMTP::mail: DSN option not supported by host';
380             }
381             }
382              
383 0 0       0 if (defined($v = delete $opt{ENVID})) {
384              
385             # expected to be in a format as required by RFC 3461, xtext-encoded
386 0 0       0 if (exists $esmtp->{DSN}) {
387 0         0 $opts .= " ENVID=$v";
388             }
389             else {
390 0         0 carp 'Net::SMTP::mail: DSN option not supported by host';
391             }
392             }
393              
394 0 0       0 if (defined($v = delete $opt{AUTH})) {
395              
396             # expected to be in a format as required by RFC 2554,
397             # rfc2821-quoted and xtext-encoded, or <>
398 0 0       0 if (exists $esmtp->{AUTH}) {
399 0 0 0     0 $v = '<>' if !defined($v) || $v eq '';
400 0         0 $opts .= " AUTH=$v";
401             }
402             else {
403 0         0 carp 'Net::SMTP::mail: AUTH option not supported by host';
404             }
405             }
406              
407 0 0       0 if (defined($v = delete $opt{XVERP})) {
408 0 0       0 if (exists $esmtp->{'XVERP'}) {
409 0         0 $opts .= " XVERP";
410             }
411             else {
412 0         0 carp 'Net::SMTP::mail: XVERP option not supported by host';
413             }
414             }
415              
416 0 0       0 carp 'Net::SMTP::recipient: unknown option(s) ' . join(" ", keys %opt) . ' - ignored'
417             if scalar keys %opt;
418             }
419             else {
420 0         0 carp 'Net::SMTP::mail: ESMTP not supported by host - options discarded :-(';
421             }
422             }
423              
424 0         0 $me->_MAIL("FROM:" . $addr . $opts);
425             }
426              
427              
428 0     0 1 0 sub send { my $me = shift; $me->_SEND("FROM:" . _addr($me, $_[0])) }
  0         0  
429 0     0 1 0 sub send_or_mail { my $me = shift; $me->_SOML("FROM:" . _addr($me, $_[0])) }
  0         0  
430 0     0 1 0 sub send_and_mail { my $me = shift; $me->_SAML("FROM:" . _addr($me, $_[0])) }
  0         0  
431              
432              
433             sub reset {
434 0     0 1 0 my $me = shift;
435              
436             $me->dataend()
437 0 0       0 if (exists ${*$me}{'net_smtp_lastch'});
  0         0  
438              
439 0         0 $me->_RSET();
440             }
441              
442              
443             sub recipient {
444 0     0 1 0 my $smtp = shift;
445 0         0 my $opts = "";
446 0         0 my $skip_bad = 0;
447              
448 0 0 0     0 if (@_ && ref($_[-1])) {
449 0         0 my %opt = %{pop(@_)};
  0         0  
450 0         0 my $v;
451              
452 0         0 $skip_bad = delete $opt{'SkipBad'};
453              
454 0 0       0 if (exists ${*$smtp}{'net_smtp_esmtp'}) {
  0 0       0  
455 0         0 my $esmtp = ${*$smtp}{'net_smtp_esmtp'};
  0         0  
456              
457 0 0       0 if (defined($v = delete $opt{Notify})) {
458 0 0       0 if (exists $esmtp->{DSN}) {
459 0         0 $opts .= " NOTIFY=" . join(",", map { uc $_ } @$v);
  0         0  
460             }
461             else {
462 0         0 carp 'Net::SMTP::recipient: DSN option not supported by host';
463             }
464             }
465              
466 0 0       0 if (defined($v = delete $opt{ORcpt})) {
467 0 0       0 if (exists $esmtp->{DSN}) {
468 0         0 $opts .= " ORCPT=" . $v;
469             }
470             else {
471 0         0 carp 'Net::SMTP::recipient: DSN option not supported by host';
472             }
473             }
474              
475 0 0       0 carp 'Net::SMTP::recipient: unknown option(s) ' . join(" ", keys %opt) . ' - ignored'
476             if scalar keys %opt;
477             }
478             elsif (%opt) {
479 0         0 carp 'Net::SMTP::recipient: ESMTP not supported by host - options discarded :-(';
480             }
481             }
482              
483 0         0 my @ok;
484 0         0 foreach my $addr (@_) {
485 0 0       0 if ($smtp->_RCPT("TO:" . _addr($smtp, $addr) . $opts)) {
    0          
486 0 0       0 push(@ok, $addr) if $skip_bad;
487             }
488             elsif (!$skip_bad) {
489 0         0 return 0;
490             }
491             }
492              
493 0 0       0 return $skip_bad ? @ok : 1;
494             }
495              
496             BEGIN {
497 6     6   30 *to = \&recipient;
498 6         12 *cc = \&recipient;
499 6         5944 *bcc = \&recipient;
500             }
501              
502              
503             sub data {
504 0     0 1 0 my $me = shift;
505              
506 0 0       0 if (exists ${*$me}{'net_smtp_chunking'}) {
  0         0  
507 0         0 carp 'Net::SMTP::data: CHUNKING extension in use, must call bdat instead';
508             }
509             else {
510 0   0     0 my $ok = $me->_DATA() && $me->datasend(@_);
511              
512 0 0 0     0 $ok && @_
513             ? $me->dataend
514             : $ok;
515             }
516             }
517              
518              
519             sub bdat {
520 0     0 1 0 my $me = shift;
521              
522 0 0       0 if (exists ${*$me}{'net_smtp_chunking'}) {
  0         0  
523 0         0 my $data = shift;
524              
525 0 0 0     0 $me->_BDAT(length $data)
526             && $me->rawdatasend($data)
527             && $me->response() == CMD_OK;
528             }
529             else {
530 0         0 carp 'Net::SMTP::bdat: CHUNKING extension is not in use, call data instead';
531             }
532             }
533              
534              
535             sub bdatlast {
536 0     0 1 0 my $me = shift;
537              
538 0 0       0 if (exists ${*$me}{'net_smtp_chunking'}) {
  0         0  
539 0         0 my $data = shift;
540              
541 0 0 0     0 $me->_BDAT(length $data, "LAST")
542             && $me->rawdatasend($data)
543             && $me->response() == CMD_OK;
544             }
545             else {
546 0         0 carp 'Net::SMTP::bdat: CHUNKING extension is not in use, call data instead';
547             }
548             }
549              
550              
551             sub datafh {
552 0     0 0 0 my $me = shift;
553 0 0       0 return unless $me->_DATA();
554 0         0 return $me->tied_fh;
555             }
556              
557              
558             sub expand {
559 0     0 1 0 my $me = shift;
560              
561 0 0       0 $me->_EXPN(@_)
562             ? ($me->message)
563             : ();
564             }
565              
566              
567 0     0 1 0 sub verify { shift->_VRFY(@_) }
568              
569              
570             sub help {
571 0     0 1 0 my $me = shift;
572              
573 0 0       0 $me->_HELP(@_)
574             ? scalar $me->message
575             : undef;
576             }
577              
578              
579             sub quit {
580 3     3 1 2851 my $me = shift;
581              
582 3         46 $me->_QUIT;
583 3         22 $me->close;
584             }
585              
586              
587       0     sub DESTROY {
588              
589             # ignore
590             }
591              
592             ##
593             ## RFC821 commands
594             ##
595              
596              
597 4     4   64 sub _EHLO { shift->command("EHLO", @_)->response() == CMD_OK }
598 0     0   0 sub _HELO { shift->command("HELO", @_)->response() == CMD_OK }
599 0     0   0 sub _MAIL { shift->command("MAIL", @_)->response() == CMD_OK }
600 0     0   0 sub _RCPT { shift->command("RCPT", @_)->response() == CMD_OK }
601 0     0   0 sub _SEND { shift->command("SEND", @_)->response() == CMD_OK }
602 0     0   0 sub _SAML { shift->command("SAML", @_)->response() == CMD_OK }
603 0     0   0 sub _SOML { shift->command("SOML", @_)->response() == CMD_OK }
604 0     0   0 sub _VRFY { shift->command("VRFY", @_)->response() == CMD_OK }
605 0     0   0 sub _EXPN { shift->command("EXPN", @_)->response() == CMD_OK }
606 0     0   0 sub _HELP { shift->command("HELP", @_)->response() == CMD_OK }
607 0     0   0 sub _RSET { shift->command("RSET")->response() == CMD_OK }
608 0     0   0 sub _NOOP { shift->command("NOOP")->response() == CMD_OK }
609 3     3   16 sub _QUIT { shift->command("QUIT")->response() == CMD_OK }
610 0     0   0 sub _DATA { shift->command("DATA")->response() == CMD_MORE }
611 0     0   0 sub _BDAT { shift->command("BDAT", @_) }
612 0     0   0 sub _TURN { shift->unsupported(@_); }
613 0     0   0 sub _ETRN { shift->command("ETRN", @_)->response() == CMD_OK }
614 0     0   0 sub _AUTH { shift->command("AUTH", @_)->response() == CMD_OK }
615 1     1   5 sub _STARTTLS { shift->command("STARTTLS")->response() == CMD_OK }
616              
617              
618             {
619             package Net::SMTP::_SSL;
620             our @ISA = ( $ssl_class ? ($ssl_class):(), 'Net::SMTP' );
621 0     0   0 sub starttls { die "SMTP connection is already in SSL mode" }
622             sub start_SSL {
623 3     3   18 my ($class,$smtp,%arg) = @_;
624 3         12 delete @arg{ grep { !m{^SSL_} } keys %arg };
  16         104  
625 3   33     14 ( $arg{SSL_verifycn_name} ||= $smtp->host )
626             =~s{(?
627             $arg{SSL_hostname} = $arg{SSL_verifycn_name}
628 3 50 33     121 if ! defined $arg{SSL_hostname} && $class->can_client_sni;
629 3   50     43 $arg{SSL_verifycn_scheme} ||= 'smtp';
630 3         49 my $ok = $class->SUPER::start_SSL($smtp,%arg);
631 3 50       21866 $@ = $ssl_class->errstr if !$ok;
632 3         11 return $ok;
633             }
634             }
635              
636              
637              
638             1;
639              
640             __END__