1 | # Net::SMTP.pm
|
---|
2 | #
|
---|
3 | # Copyright (c) 1995-2004 Graham Barr <gbarr@pobox.com>. All rights reserved.
|
---|
4 | # This program is free software; you can redistribute it and/or
|
---|
5 | # modify it under the same terms as Perl itself.
|
---|
6 |
|
---|
7 | package Net::SMTP;
|
---|
8 |
|
---|
9 | require 5.001;
|
---|
10 |
|
---|
11 | use strict;
|
---|
12 | use vars qw($VERSION @ISA);
|
---|
13 | use Socket 1.3;
|
---|
14 | use Carp;
|
---|
15 | use IO::Socket;
|
---|
16 | use Net::Cmd;
|
---|
17 | use Net::Config;
|
---|
18 |
|
---|
19 | $VERSION = "2.29";
|
---|
20 |
|
---|
21 | @ISA = qw(Net::Cmd IO::Socket::INET);
|
---|
22 |
|
---|
23 | sub new
|
---|
24 | {
|
---|
25 | my $self = shift;
|
---|
26 | my $type = ref($self) || $self;
|
---|
27 | my ($host,%arg);
|
---|
28 | if (@_ % 2) {
|
---|
29 | $host = shift ;
|
---|
30 | %arg = @_;
|
---|
31 | } else {
|
---|
32 | %arg = @_;
|
---|
33 | $host=delete $arg{Host};
|
---|
34 | }
|
---|
35 | my $hosts = defined $host ? $host : $NetConfig{smtp_hosts};
|
---|
36 | my $obj;
|
---|
37 |
|
---|
38 | my $h;
|
---|
39 | foreach $h (@{ref($hosts) ? $hosts : [ $hosts ]})
|
---|
40 | {
|
---|
41 | $obj = $type->SUPER::new(PeerAddr => ($host = $h),
|
---|
42 | PeerPort => $arg{Port} || 'smtp(25)',
|
---|
43 | LocalAddr => $arg{LocalAddr},
|
---|
44 | LocalPort => $arg{LocalPort},
|
---|
45 | Proto => 'tcp',
|
---|
46 | Timeout => defined $arg{Timeout}
|
---|
47 | ? $arg{Timeout}
|
---|
48 | : 120
|
---|
49 | ) and last;
|
---|
50 | }
|
---|
51 |
|
---|
52 | return undef
|
---|
53 | unless defined $obj;
|
---|
54 |
|
---|
55 | $obj->autoflush(1);
|
---|
56 |
|
---|
57 | $obj->debug(exists $arg{Debug} ? $arg{Debug} : undef);
|
---|
58 |
|
---|
59 | unless ($obj->response() == CMD_OK)
|
---|
60 | {
|
---|
61 | $obj->close();
|
---|
62 | return undef;
|
---|
63 | }
|
---|
64 |
|
---|
65 | ${*$obj}{'net_smtp_exact_addr'} = $arg{ExactAddresses};
|
---|
66 | ${*$obj}{'net_smtp_host'} = $host;
|
---|
67 |
|
---|
68 | (${*$obj}{'net_smtp_banner'}) = $obj->message;
|
---|
69 | (${*$obj}{'net_smtp_domain'}) = $obj->message =~ /\A\s*(\S+)/;
|
---|
70 |
|
---|
71 | unless($obj->hello($arg{Hello} || ""))
|
---|
72 | {
|
---|
73 | $obj->close();
|
---|
74 | return undef;
|
---|
75 | }
|
---|
76 |
|
---|
77 | $obj;
|
---|
78 | }
|
---|
79 |
|
---|
80 | sub host {
|
---|
81 | my $me = shift;
|
---|
82 | ${*$me}{'net_smtp_host'};
|
---|
83 | }
|
---|
84 |
|
---|
85 | ##
|
---|
86 | ## User interface methods
|
---|
87 | ##
|
---|
88 |
|
---|
89 | sub banner
|
---|
90 | {
|
---|
91 | my $me = shift;
|
---|
92 |
|
---|
93 | return ${*$me}{'net_smtp_banner'} || undef;
|
---|
94 | }
|
---|
95 |
|
---|
96 | sub domain
|
---|
97 | {
|
---|
98 | my $me = shift;
|
---|
99 |
|
---|
100 | return ${*$me}{'net_smtp_domain'} || undef;
|
---|
101 | }
|
---|
102 |
|
---|
103 | sub etrn {
|
---|
104 | my $self = shift;
|
---|
105 | defined($self->supports('ETRN',500,["Command unknown: 'ETRN'"])) &&
|
---|
106 | $self->_ETRN(@_);
|
---|
107 | }
|
---|
108 |
|
---|
109 | sub auth {
|
---|
110 | my ($self, $username, $password) = @_;
|
---|
111 |
|
---|
112 | eval {
|
---|
113 | require MIME::Base64;
|
---|
114 | require Authen::SASL;
|
---|
115 | } or $self->set_status(500,["Need MIME::Base64 and Authen::SASL todo auth"]), return 0;
|
---|
116 |
|
---|
117 | my $mechanisms = $self->supports('AUTH',500,["Command unknown: 'AUTH'"]);
|
---|
118 | return unless defined $mechanisms;
|
---|
119 |
|
---|
120 | my $sasl;
|
---|
121 |
|
---|
122 | if (ref($username) and UNIVERSAL::isa($username,'Authen::SASL')) {
|
---|
123 | $sasl = $username;
|
---|
124 | $sasl->mechanism($mechanisms);
|
---|
125 | }
|
---|
126 | else {
|
---|
127 | die "auth(username, password)" if not length $username;
|
---|
128 | $sasl = Authen::SASL->new(mechanism=> $mechanisms,
|
---|
129 | callback => { user => $username,
|
---|
130 | pass => $password,
|
---|
131 | authname => $username,
|
---|
132 | });
|
---|
133 | }
|
---|
134 |
|
---|
135 | # We should probably allow the user to pass the host, but I don't
|
---|
136 | # currently know and SASL mechanisms that are used by smtp that need it
|
---|
137 | my $client = $sasl->client_new('smtp',${*$self}{'net_smtp_host'},0);
|
---|
138 | my $str = $client->client_start;
|
---|
139 | # We dont support sasl mechanisms that encrypt the socket traffic.
|
---|
140 | # todo that we would really need to change the ISA hierarchy
|
---|
141 | # so we dont inherit from IO::Socket, but instead hold it in an attribute
|
---|
142 |
|
---|
143 | my @cmd = ("AUTH", $client->mechanism);
|
---|
144 | my $code;
|
---|
145 |
|
---|
146 | push @cmd, MIME::Base64::encode_base64($str,'')
|
---|
147 | if defined $str and length $str;
|
---|
148 |
|
---|
149 | while (($code = $self->command(@cmd)->response()) == CMD_MORE) {
|
---|
150 | @cmd = (MIME::Base64::encode_base64(
|
---|
151 | $client->client_step(
|
---|
152 | MIME::Base64::decode_base64(
|
---|
153 | ($self->message)[0]
|
---|
154 | )
|
---|
155 | ), ''
|
---|
156 | ));
|
---|
157 | }
|
---|
158 |
|
---|
159 | $code == CMD_OK;
|
---|
160 | }
|
---|
161 |
|
---|
162 | sub hello
|
---|
163 | {
|
---|
164 | my $me = shift;
|
---|
165 | my $domain = shift || "localhost.localdomain";
|
---|
166 | my $ok = $me->_EHLO($domain);
|
---|
167 | my @msg = $me->message;
|
---|
168 |
|
---|
169 | if($ok)
|
---|
170 | {
|
---|
171 | my $h = ${*$me}{'net_smtp_esmtp'} = {};
|
---|
172 | my $ln;
|
---|
173 | foreach $ln (@msg) {
|
---|
174 | $h->{uc $1} = $2
|
---|
175 | if $ln =~ /(\w+)\b[= \t]*([^\n]*)/;
|
---|
176 | }
|
---|
177 | }
|
---|
178 | elsif($me->status == CMD_ERROR)
|
---|
179 | {
|
---|
180 | @msg = $me->message
|
---|
181 | if $ok = $me->_HELO($domain);
|
---|
182 | }
|
---|
183 |
|
---|
184 | return undef unless $ok;
|
---|
185 |
|
---|
186 | $msg[0] =~ /\A\s*(\S+)/;
|
---|
187 | return ($1 || " ");
|
---|
188 | }
|
---|
189 |
|
---|
190 | sub supports {
|
---|
191 | my $self = shift;
|
---|
192 | my $cmd = uc shift;
|
---|
193 | return ${*$self}{'net_smtp_esmtp'}->{$cmd}
|
---|
194 | if exists ${*$self}{'net_smtp_esmtp'}->{$cmd};
|
---|
195 | $self->set_status(@_)
|
---|
196 | if @_;
|
---|
197 | return;
|
---|
198 | }
|
---|
199 |
|
---|
200 | sub _addr {
|
---|
201 | my $self = shift;
|
---|
202 | my $addr = shift;
|
---|
203 | $addr = "" unless defined $addr;
|
---|
204 |
|
---|
205 | if (${*$self}{'net_smtp_exact_addr'}) {
|
---|
206 | return $1 if $addr =~ /^\s*(<.*>)\s*$/s;
|
---|
207 | }
|
---|
208 | else {
|
---|
209 | return $1 if $addr =~ /(<[^>]*>)/;
|
---|
210 | $addr =~ s/^\s+|\s+$//sg;
|
---|
211 | }
|
---|
212 |
|
---|
213 | "<$addr>";
|
---|
214 | }
|
---|
215 |
|
---|
216 | sub mail
|
---|
217 | {
|
---|
218 | my $me = shift;
|
---|
219 | my $addr = _addr($me, shift);
|
---|
220 | my $opts = "";
|
---|
221 |
|
---|
222 | if(@_)
|
---|
223 | {
|
---|
224 | my %opt = @_;
|
---|
225 | my($k,$v);
|
---|
226 |
|
---|
227 | if(exists ${*$me}{'net_smtp_esmtp'})
|
---|
228 | {
|
---|
229 | my $esmtp = ${*$me}{'net_smtp_esmtp'};
|
---|
230 |
|
---|
231 | if(defined($v = delete $opt{Size}))
|
---|
232 | {
|
---|
233 | if(exists $esmtp->{SIZE})
|
---|
234 | {
|
---|
235 | $opts .= sprintf " SIZE=%d", $v + 0
|
---|
236 | }
|
---|
237 | else
|
---|
238 | {
|
---|
239 | carp 'Net::SMTP::mail: SIZE option not supported by host';
|
---|
240 | }
|
---|
241 | }
|
---|
242 |
|
---|
243 | if(defined($v = delete $opt{Return}))
|
---|
244 | {
|
---|
245 | if(exists $esmtp->{DSN})
|
---|
246 | {
|
---|
247 | $opts .= " RET=" . ((uc($v) eq "FULL") ? "FULL" : "HDRS");
|
---|
248 | }
|
---|
249 | else
|
---|
250 | {
|
---|
251 | carp 'Net::SMTP::mail: DSN option not supported by host';
|
---|
252 | }
|
---|
253 | }
|
---|
254 |
|
---|
255 | if(defined($v = delete $opt{Bits}))
|
---|
256 | {
|
---|
257 | if($v eq "8")
|
---|
258 | {
|
---|
259 | if(exists $esmtp->{'8BITMIME'})
|
---|
260 | {
|
---|
261 | $opts .= " BODY=8BITMIME";
|
---|
262 | }
|
---|
263 | else
|
---|
264 | {
|
---|
265 | carp 'Net::SMTP::mail: 8BITMIME option not supported by host';
|
---|
266 | }
|
---|
267 | }
|
---|
268 | elsif($v eq "binary")
|
---|
269 | {
|
---|
270 | if(exists $esmtp->{'BINARYMIME'} && exists $esmtp->{'CHUNKING'})
|
---|
271 | {
|
---|
272 | $opts .= " BODY=BINARYMIME";
|
---|
273 | ${*$me}{'net_smtp_chunking'} = 1;
|
---|
274 | }
|
---|
275 | else
|
---|
276 | {
|
---|
277 | carp 'Net::SMTP::mail: BINARYMIME option not supported by host';
|
---|
278 | }
|
---|
279 | }
|
---|
280 | elsif(exists $esmtp->{'8BITMIME'} or exists $esmtp->{'BINARYMIME'})
|
---|
281 | {
|
---|
282 | $opts .= " BODY=7BIT";
|
---|
283 | }
|
---|
284 | else
|
---|
285 | {
|
---|
286 | carp 'Net::SMTP::mail: 8BITMIME and BINARYMIME options not supported by host';
|
---|
287 | }
|
---|
288 | }
|
---|
289 |
|
---|
290 | if(defined($v = delete $opt{Transaction}))
|
---|
291 | {
|
---|
292 | if(exists $esmtp->{CHECKPOINT})
|
---|
293 | {
|
---|
294 | $opts .= " TRANSID=" . _addr($me, $v);
|
---|
295 | }
|
---|
296 | else
|
---|
297 | {
|
---|
298 | carp 'Net::SMTP::mail: CHECKPOINT option not supported by host';
|
---|
299 | }
|
---|
300 | }
|
---|
301 |
|
---|
302 | if(defined($v = delete $opt{Envelope}))
|
---|
303 | {
|
---|
304 | if(exists $esmtp->{DSN})
|
---|
305 | {
|
---|
306 | $v =~ s/([^\041-\176]|=|\+)/sprintf "+%02x", ord($1)/sge;
|
---|
307 | $opts .= " ENVID=$v"
|
---|
308 | }
|
---|
309 | else
|
---|
310 | {
|
---|
311 | carp 'Net::SMTP::mail: DSN option not supported by host';
|
---|
312 | }
|
---|
313 | }
|
---|
314 |
|
---|
315 | if(defined($v = delete $opt{XVERP}))
|
---|
316 | {
|
---|
317 | if(exists $esmtp->{'XVERP'})
|
---|
318 | {
|
---|
319 | $opts .= " XVERP"
|
---|
320 | }
|
---|
321 | else
|
---|
322 | {
|
---|
323 | carp 'Net::SMTP::mail: XVERP option not supported by host';
|
---|
324 | }
|
---|
325 | }
|
---|
326 |
|
---|
327 | carp 'Net::SMTP::recipient: unknown option(s) '
|
---|
328 | . join(" ", keys %opt)
|
---|
329 | . ' - ignored'
|
---|
330 | if scalar keys %opt;
|
---|
331 | }
|
---|
332 | else
|
---|
333 | {
|
---|
334 | carp 'Net::SMTP::mail: ESMTP not supported by host - options discarded :-(';
|
---|
335 | }
|
---|
336 | }
|
---|
337 |
|
---|
338 | $me->_MAIL("FROM:".$addr.$opts);
|
---|
339 | }
|
---|
340 |
|
---|
341 | sub send { my $me = shift; $me->_SEND("FROM:" . _addr($me, $_[0])) }
|
---|
342 | sub send_or_mail { my $me = shift; $me->_SOML("FROM:" . _addr($me, $_[0])) }
|
---|
343 | sub send_and_mail { my $me = shift; $me->_SAML("FROM:" . _addr($me, $_[0])) }
|
---|
344 |
|
---|
345 | sub reset
|
---|
346 | {
|
---|
347 | my $me = shift;
|
---|
348 |
|
---|
349 | $me->dataend()
|
---|
350 | if(exists ${*$me}{'net_smtp_lastch'});
|
---|
351 |
|
---|
352 | $me->_RSET();
|
---|
353 | }
|
---|
354 |
|
---|
355 |
|
---|
356 | sub recipient
|
---|
357 | {
|
---|
358 | my $smtp = shift;
|
---|
359 | my $opts = "";
|
---|
360 | my $skip_bad = 0;
|
---|
361 |
|
---|
362 | if(@_ && ref($_[-1]))
|
---|
363 | {
|
---|
364 | my %opt = %{pop(@_)};
|
---|
365 | my $v;
|
---|
366 |
|
---|
367 | $skip_bad = delete $opt{'SkipBad'};
|
---|
368 |
|
---|
369 | if(exists ${*$smtp}{'net_smtp_esmtp'})
|
---|
370 | {
|
---|
371 | my $esmtp = ${*$smtp}{'net_smtp_esmtp'};
|
---|
372 |
|
---|
373 | if(defined($v = delete $opt{Notify}))
|
---|
374 | {
|
---|
375 | if(exists $esmtp->{DSN})
|
---|
376 | {
|
---|
377 | $opts .= " NOTIFY=" . join(",",map { uc $_ } @$v)
|
---|
378 | }
|
---|
379 | else
|
---|
380 | {
|
---|
381 | carp 'Net::SMTP::recipient: DSN option not supported by host';
|
---|
382 | }
|
---|
383 | }
|
---|
384 |
|
---|
385 | carp 'Net::SMTP::recipient: unknown option(s) '
|
---|
386 | . join(" ", keys %opt)
|
---|
387 | . ' - ignored'
|
---|
388 | if scalar keys %opt;
|
---|
389 | }
|
---|
390 | elsif(%opt)
|
---|
391 | {
|
---|
392 | carp 'Net::SMTP::recipient: ESMTP not supported by host - options discarded :-(';
|
---|
393 | }
|
---|
394 | }
|
---|
395 |
|
---|
396 | my @ok;
|
---|
397 | my $addr;
|
---|
398 | foreach $addr (@_)
|
---|
399 | {
|
---|
400 | if($smtp->_RCPT("TO:" . _addr($smtp, $addr) . $opts)) {
|
---|
401 | push(@ok,$addr) if $skip_bad;
|
---|
402 | }
|
---|
403 | elsif(!$skip_bad) {
|
---|
404 | return 0;
|
---|
405 | }
|
---|
406 | }
|
---|
407 |
|
---|
408 | return $skip_bad ? @ok : 1;
|
---|
409 | }
|
---|
410 |
|
---|
411 | BEGIN {
|
---|
412 | *to = \&recipient;
|
---|
413 | *cc = \&recipient;
|
---|
414 | *bcc = \&recipient;
|
---|
415 | }
|
---|
416 |
|
---|
417 | sub data
|
---|
418 | {
|
---|
419 | my $me = shift;
|
---|
420 |
|
---|
421 | if(exists ${*$me}{'net_smtp_chunking'})
|
---|
422 | {
|
---|
423 | carp 'Net::SMTP::data: CHUNKING extension in use, must call bdat instead';
|
---|
424 | }
|
---|
425 | else
|
---|
426 | {
|
---|
427 | my $ok = $me->_DATA() && $me->datasend(@_);
|
---|
428 |
|
---|
429 | $ok && @_ ? $me->dataend
|
---|
430 | : $ok;
|
---|
431 | }
|
---|
432 | }
|
---|
433 |
|
---|
434 | sub bdat
|
---|
435 | {
|
---|
436 | my $me = shift;
|
---|
437 |
|
---|
438 | if(exists ${*$me}{'net_smtp_chunking'})
|
---|
439 | {
|
---|
440 | my $data = shift;
|
---|
441 |
|
---|
442 | $me->_BDAT(length $data) && $me->rawdatasend($data) &&
|
---|
443 | $me->response() == CMD_OK;
|
---|
444 | }
|
---|
445 | else
|
---|
446 | {
|
---|
447 | carp 'Net::SMTP::bdat: CHUNKING extension is not in use, call data instead';
|
---|
448 | }
|
---|
449 | }
|
---|
450 |
|
---|
451 | sub bdatlast
|
---|
452 | {
|
---|
453 | my $me = shift;
|
---|
454 |
|
---|
455 | if(exists ${*$me}{'net_smtp_chunking'})
|
---|
456 | {
|
---|
457 | my $data = shift;
|
---|
458 |
|
---|
459 | $me->_BDAT(length $data, "LAST") && $me->rawdatasend($data) &&
|
---|
460 | $me->response() == CMD_OK;
|
---|
461 | }
|
---|
462 | else
|
---|
463 | {
|
---|
464 | carp 'Net::SMTP::bdat: CHUNKING extension is not in use, call data instead';
|
---|
465 | }
|
---|
466 | }
|
---|
467 |
|
---|
468 | sub datafh {
|
---|
469 | my $me = shift;
|
---|
470 | return unless $me->_DATA();
|
---|
471 | return $me->tied_fh;
|
---|
472 | }
|
---|
473 |
|
---|
474 | sub expand
|
---|
475 | {
|
---|
476 | my $me = shift;
|
---|
477 |
|
---|
478 | $me->_EXPN(@_) ? ($me->message)
|
---|
479 | : ();
|
---|
480 | }
|
---|
481 |
|
---|
482 |
|
---|
483 | sub verify { shift->_VRFY(@_) }
|
---|
484 |
|
---|
485 | sub help
|
---|
486 | {
|
---|
487 | my $me = shift;
|
---|
488 |
|
---|
489 | $me->_HELP(@_) ? scalar $me->message
|
---|
490 | : undef;
|
---|
491 | }
|
---|
492 |
|
---|
493 | sub quit
|
---|
494 | {
|
---|
495 | my $me = shift;
|
---|
496 |
|
---|
497 | $me->_QUIT;
|
---|
498 | $me->close;
|
---|
499 | }
|
---|
500 |
|
---|
501 | sub DESTROY
|
---|
502 | {
|
---|
503 | # ignore
|
---|
504 | }
|
---|
505 |
|
---|
506 | ##
|
---|
507 | ## RFC821 commands
|
---|
508 | ##
|
---|
509 |
|
---|
510 | sub _EHLO { shift->command("EHLO", @_)->response() == CMD_OK }
|
---|
511 | sub _HELO { shift->command("HELO", @_)->response() == CMD_OK }
|
---|
512 | sub _MAIL { shift->command("MAIL", @_)->response() == CMD_OK }
|
---|
513 | sub _RCPT { shift->command("RCPT", @_)->response() == CMD_OK }
|
---|
514 | sub _SEND { shift->command("SEND", @_)->response() == CMD_OK }
|
---|
515 | sub _SAML { shift->command("SAML", @_)->response() == CMD_OK }
|
---|
516 | sub _SOML { shift->command("SOML", @_)->response() == CMD_OK }
|
---|
517 | sub _VRFY { shift->command("VRFY", @_)->response() == CMD_OK }
|
---|
518 | sub _EXPN { shift->command("EXPN", @_)->response() == CMD_OK }
|
---|
519 | sub _HELP { shift->command("HELP", @_)->response() == CMD_OK }
|
---|
520 | sub _RSET { shift->command("RSET")->response() == CMD_OK }
|
---|
521 | sub _NOOP { shift->command("NOOP")->response() == CMD_OK }
|
---|
522 | sub _QUIT { shift->command("QUIT")->response() == CMD_OK }
|
---|
523 | sub _DATA { shift->command("DATA")->response() == CMD_MORE }
|
---|
524 | sub _BDAT { shift->command("BDAT", @_) }
|
---|
525 | sub _TURN { shift->unsupported(@_); }
|
---|
526 | sub _ETRN { shift->command("ETRN", @_)->response() == CMD_OK }
|
---|
527 | sub _AUTH { shift->command("AUTH", @_)->response() == CMD_OK }
|
---|
528 |
|
---|
529 | 1;
|
---|
530 |
|
---|
531 | __END__
|
---|
532 |
|
---|
533 | =head1 NAME
|
---|
534 |
|
---|
535 | Net::SMTP - Simple Mail Transfer Protocol Client
|
---|
536 |
|
---|
537 | =head1 SYNOPSIS
|
---|
538 |
|
---|
539 | use Net::SMTP;
|
---|
540 |
|
---|
541 | # Constructors
|
---|
542 | $smtp = Net::SMTP->new('mailhost');
|
---|
543 | $smtp = Net::SMTP->new('mailhost', Timeout => 60);
|
---|
544 |
|
---|
545 | =head1 DESCRIPTION
|
---|
546 |
|
---|
547 | This module implements a client interface to the SMTP and ESMTP
|
---|
548 | protocol, enabling a perl5 application to talk to SMTP servers. This
|
---|
549 | documentation assumes that you are familiar with the concepts of the
|
---|
550 | SMTP protocol described in RFC821.
|
---|
551 |
|
---|
552 | A new Net::SMTP object must be created with the I<new> method. Once
|
---|
553 | this has been done, all SMTP commands are accessed through this object.
|
---|
554 |
|
---|
555 | The Net::SMTP class is a subclass of Net::Cmd and IO::Socket::INET.
|
---|
556 |
|
---|
557 | =head1 EXAMPLES
|
---|
558 |
|
---|
559 | This example prints the mail domain name of the SMTP server known as mailhost:
|
---|
560 |
|
---|
561 | #!/usr/local/bin/perl -w
|
---|
562 |
|
---|
563 | use Net::SMTP;
|
---|
564 |
|
---|
565 | $smtp = Net::SMTP->new('mailhost');
|
---|
566 | print $smtp->domain,"\n";
|
---|
567 | $smtp->quit;
|
---|
568 |
|
---|
569 | This example sends a small message to the postmaster at the SMTP server
|
---|
570 | known as mailhost:
|
---|
571 |
|
---|
572 | #!/usr/local/bin/perl -w
|
---|
573 |
|
---|
574 | use Net::SMTP;
|
---|
575 |
|
---|
576 | $smtp = Net::SMTP->new('mailhost');
|
---|
577 |
|
---|
578 | $smtp->mail($ENV{USER});
|
---|
579 | $smtp->to('postmaster');
|
---|
580 |
|
---|
581 | $smtp->data();
|
---|
582 | $smtp->datasend("To: postmaster\n");
|
---|
583 | $smtp->datasend("\n");
|
---|
584 | $smtp->datasend("A simple test message\n");
|
---|
585 | $smtp->dataend();
|
---|
586 |
|
---|
587 | $smtp->quit;
|
---|
588 |
|
---|
589 | =head1 CONSTRUCTOR
|
---|
590 |
|
---|
591 | =over 4
|
---|
592 |
|
---|
593 | =item new ( [ HOST ] [, OPTIONS ] )
|
---|
594 |
|
---|
595 | This is the constructor for a new Net::SMTP object. C<HOST> is the
|
---|
596 | name of the remote host to which an SMTP connection is required.
|
---|
597 |
|
---|
598 | C<HOST> is optional. If C<HOST> is not given then it may instead be
|
---|
599 | passed as the C<Host> option described below. If neither is given then
|
---|
600 | the C<SMTP_Hosts> specified in C<Net::Config> will be used.
|
---|
601 |
|
---|
602 | C<OPTIONS> are passed in a hash like fashion, using key and value pairs.
|
---|
603 | Possible options are:
|
---|
604 |
|
---|
605 | B<Hello> - SMTP requires that you identify yourself. This option
|
---|
606 | specifies a string to pass as your mail domain. If not given localhost.localdomain
|
---|
607 | will be used.
|
---|
608 |
|
---|
609 | B<Host> - SMTP host to connect to. It may be a single scalar, as defined for
|
---|
610 | the C<PeerAddr> option in L<IO::Socket::INET>, or a reference to
|
---|
611 | an array with hosts to try in turn. The L</host> method will return the value
|
---|
612 | which was used to connect to the host.
|
---|
613 |
|
---|
614 | B<LocalAddr> and B<LocalPort> - These parameters are passed directly
|
---|
615 | to IO::Socket to allow binding the socket to a local port.
|
---|
616 |
|
---|
617 | B<Timeout> - Maximum time, in seconds, to wait for a response from the
|
---|
618 | SMTP server (default: 120)
|
---|
619 |
|
---|
620 | B<ExactAddresses> - If true the all ADDRESS arguments must be as
|
---|
621 | defined by C<addr-spec> in RFC2822. If not given, or false, then
|
---|
622 | Net::SMTP will attempt to extract the address from the value passed.
|
---|
623 |
|
---|
624 | B<Debug> - Enable debugging information
|
---|
625 |
|
---|
626 |
|
---|
627 | Example:
|
---|
628 |
|
---|
629 |
|
---|
630 | $smtp = Net::SMTP->new('mailhost',
|
---|
631 | Hello => 'my.mail.domain'
|
---|
632 | Timeout => 30,
|
---|
633 | Debug => 1,
|
---|
634 | );
|
---|
635 |
|
---|
636 | # the same
|
---|
637 | $smtp = Net::SMTP->new(
|
---|
638 | Host => 'mailhost',
|
---|
639 | Hello => 'my.mail.domain'
|
---|
640 | Timeout => 30,
|
---|
641 | Debug => 1,
|
---|
642 | );
|
---|
643 |
|
---|
644 | # Connect to the default server from Net::config
|
---|
645 | $smtp = Net::SMTP->new(
|
---|
646 | Hello => 'my.mail.domain'
|
---|
647 | Timeout => 30,
|
---|
648 | );
|
---|
649 |
|
---|
650 | =back
|
---|
651 |
|
---|
652 | =head1 METHODS
|
---|
653 |
|
---|
654 | Unless otherwise stated all methods return either a I<true> or I<false>
|
---|
655 | value, with I<true> meaning that the operation was a success. When a method
|
---|
656 | states that it returns a value, failure will be returned as I<undef> or an
|
---|
657 | empty list.
|
---|
658 |
|
---|
659 | =over 4
|
---|
660 |
|
---|
661 | =item banner ()
|
---|
662 |
|
---|
663 | Returns the banner message which the server replied with when the
|
---|
664 | initial connection was made.
|
---|
665 |
|
---|
666 | =item domain ()
|
---|
667 |
|
---|
668 | Returns the domain that the remote SMTP server identified itself as during
|
---|
669 | connection.
|
---|
670 |
|
---|
671 | =item hello ( DOMAIN )
|
---|
672 |
|
---|
673 | Tell the remote server the mail domain which you are in using the EHLO
|
---|
674 | command (or HELO if EHLO fails). Since this method is invoked
|
---|
675 | automatically when the Net::SMTP object is constructed the user should
|
---|
676 | normally not have to call it manually.
|
---|
677 |
|
---|
678 | =item host ()
|
---|
679 |
|
---|
680 | Returns the value used by the constructor, and passed to IO::Socket::INET,
|
---|
681 | to connect to the host.
|
---|
682 |
|
---|
683 | =item etrn ( DOMAIN )
|
---|
684 |
|
---|
685 | Request a queue run for the DOMAIN given.
|
---|
686 |
|
---|
687 | =item auth ( USERNAME, PASSWORD )
|
---|
688 |
|
---|
689 | Attempt SASL authentication.
|
---|
690 |
|
---|
691 | =item mail ( ADDRESS [, OPTIONS] )
|
---|
692 |
|
---|
693 | =item send ( ADDRESS )
|
---|
694 |
|
---|
695 | =item send_or_mail ( ADDRESS )
|
---|
696 |
|
---|
697 | =item send_and_mail ( ADDRESS )
|
---|
698 |
|
---|
699 | Send the appropriate command to the server MAIL, SEND, SOML or SAML. C<ADDRESS>
|
---|
700 | is the address of the sender. This initiates the sending of a message. The
|
---|
701 | method C<recipient> should be called for each address that the message is to
|
---|
702 | be sent to.
|
---|
703 |
|
---|
704 | The C<mail> method can some additional ESMTP OPTIONS which is passed
|
---|
705 | in hash like fashion, using key and value pairs. Possible options are:
|
---|
706 |
|
---|
707 | Size => <bytes>
|
---|
708 | Return => "FULL" | "HDRS"
|
---|
709 | Bits => "7" | "8" | "binary"
|
---|
710 | Transaction => <ADDRESS>
|
---|
711 | Envelope => <ENVID>
|
---|
712 | XVERP => 1
|
---|
713 |
|
---|
714 | The C<Return> and C<Envelope> parameters are used for DSN (Delivery
|
---|
715 | Status Notification).
|
---|
716 |
|
---|
717 | =item reset ()
|
---|
718 |
|
---|
719 | Reset the status of the server. This may be called after a message has been
|
---|
720 | initiated, but before any data has been sent, to cancel the sending of the
|
---|
721 | message.
|
---|
722 |
|
---|
723 | =item recipient ( ADDRESS [, ADDRESS, [...]] [, OPTIONS ] )
|
---|
724 |
|
---|
725 | Notify the server that the current message should be sent to all of the
|
---|
726 | addresses given. Each address is sent as a separate command to the server.
|
---|
727 | Should the sending of any address result in a failure then the process is
|
---|
728 | aborted and a I<false> value is returned. It is up to the user to call
|
---|
729 | C<reset> if they so desire.
|
---|
730 |
|
---|
731 | The C<recipient> method can also pass additional case-sensitive OPTIONS as an
|
---|
732 | anonymous hash using key and value pairs. Possible options are:
|
---|
733 |
|
---|
734 | Notify => ['NEVER'] or ['SUCCESS','FAILURE','DELAY'] (see below)
|
---|
735 | SkipBad => 1 (to ignore bad addresses)
|
---|
736 |
|
---|
737 | If C<SkipBad> is true the C<recipient> will not return an error when a bad
|
---|
738 | address is encountered and it will return an array of addresses that did
|
---|
739 | succeed.
|
---|
740 |
|
---|
741 | $smtp->recipient($recipient1,$recipient2); # Good
|
---|
742 | $smtp->recipient($recipient1,$recipient2, { SkipBad => 1 }); # Good
|
---|
743 | $smtp->recipient($recipient1,$recipient2, { Notify => ['FAILURE','DELAY'], SkipBad => 1 }); # Good
|
---|
744 | @goodrecips=$smtp->recipient(@recipients, { Notify => ['FAILURE'], SkipBad => 1 }); # Good
|
---|
745 | $smtp->recipient("$recipient,$recipient2"); # BAD
|
---|
746 |
|
---|
747 | Notify is used to request Delivery Status Notifications (DSNs), but your
|
---|
748 | SMTP/ESMTP service may not respect this request depending upon its version and
|
---|
749 | your site's SMTP configuration.
|
---|
750 |
|
---|
751 | Leaving out the Notify option usually defaults an SMTP service to its default
|
---|
752 | behavior equivalent to ['FAILURE'] notifications only, but again this may be
|
---|
753 | dependent upon your site's SMTP configuration.
|
---|
754 |
|
---|
755 | The NEVER keyword must appear by itself if used within the Notify option and "requests
|
---|
756 | that a DSN not be returned to the sender under any conditions."
|
---|
757 |
|
---|
758 | {Notify => ['NEVER']}
|
---|
759 |
|
---|
760 | $smtp->recipient(@recipients, { Notify => ['NEVER'], SkipBad => 1 }); # Good
|
---|
761 |
|
---|
762 | You may use any combination of these three values 'SUCCESS','FAILURE','DELAY' in
|
---|
763 | the anonymous array reference as defined by RFC3461 (see http://rfc.net/rfc3461.html
|
---|
764 | for more information. Note: quotations in this topic from same.).
|
---|
765 |
|
---|
766 | A Notify parameter of 'SUCCESS' or 'FAILURE' "requests that a DSN be issued on
|
---|
767 | successful delivery or delivery failure, respectively."
|
---|
768 |
|
---|
769 | A Notify parameter of 'DELAY' "indicates the sender's willingness to receive
|
---|
770 | delayed DSNs. Delayed DSNs may be issued if delivery of a message has been
|
---|
771 | delayed for an unusual amount of time (as determined by the Message Transfer
|
---|
772 | Agent (MTA) at which the message is delayed), but the final delivery status
|
---|
773 | (whether successful or failure) cannot be determined. The absence of the DELAY
|
---|
774 | keyword in a NOTIFY parameter requests that a "delayed" DSN NOT be issued under
|
---|
775 | any conditions."
|
---|
776 |
|
---|
777 | {Notify => ['SUCCESS','FAILURE','DELAY']}
|
---|
778 |
|
---|
779 | $smtp->recipient(@recipients, { Notify => ['FAILURE','DELAY'], SkipBad => 1 }); # Good
|
---|
780 |
|
---|
781 | =item to ( ADDRESS [, ADDRESS [...]] )
|
---|
782 |
|
---|
783 | =item cc ( ADDRESS [, ADDRESS [...]] )
|
---|
784 |
|
---|
785 | =item bcc ( ADDRESS [, ADDRESS [...]] )
|
---|
786 |
|
---|
787 | Synonyms for C<recipient>.
|
---|
788 |
|
---|
789 | =item data ( [ DATA ] )
|
---|
790 |
|
---|
791 | Initiate the sending of the data from the current message.
|
---|
792 |
|
---|
793 | C<DATA> may be a reference to a list or a list. If specified the contents
|
---|
794 | of C<DATA> and a termination string C<".\r\n"> is sent to the server. And the
|
---|
795 | result will be true if the data was accepted.
|
---|
796 |
|
---|
797 | If C<DATA> is not specified then the result will indicate that the server
|
---|
798 | wishes the data to be sent. The data must then be sent using the C<datasend>
|
---|
799 | and C<dataend> methods described in L<Net::Cmd>.
|
---|
800 |
|
---|
801 | =item expand ( ADDRESS )
|
---|
802 |
|
---|
803 | Request the server to expand the given address Returns an array
|
---|
804 | which contains the text read from the server.
|
---|
805 |
|
---|
806 | =item verify ( ADDRESS )
|
---|
807 |
|
---|
808 | Verify that C<ADDRESS> is a legitimate mailing address.
|
---|
809 |
|
---|
810 | Most sites usually disable this feature in their SMTP service configuration.
|
---|
811 | Use "Debug => 1" option under new() to see if disabled.
|
---|
812 |
|
---|
813 | =item help ( [ $subject ] )
|
---|
814 |
|
---|
815 | Request help text from the server. Returns the text or undef upon failure
|
---|
816 |
|
---|
817 | =item quit ()
|
---|
818 |
|
---|
819 | Send the QUIT command to the remote SMTP server and close the socket connection.
|
---|
820 |
|
---|
821 | =back
|
---|
822 |
|
---|
823 | =head1 ADDRESSES
|
---|
824 |
|
---|
825 | Net::SMTP attempts to DWIM with addresses that are passed. For
|
---|
826 | example an application might extract The From: line from an email
|
---|
827 | and pass that to mail(). While this may work, it is not reccomended.
|
---|
828 | The application should really use a module like L<Mail::Address>
|
---|
829 | to extract the mail address and pass that.
|
---|
830 |
|
---|
831 | If C<ExactAddresses> is passed to the contructor, then addresses
|
---|
832 | should be a valid rfc2821-quoted address, although Net::SMTP will
|
---|
833 | accept accept the address surrounded by angle brackets.
|
---|
834 |
|
---|
835 | funny user@domain WRONG
|
---|
836 | "funny user"@domain RIGHT, recommended
|
---|
837 | <"funny user"@domain> OK
|
---|
838 |
|
---|
839 | =head1 SEE ALSO
|
---|
840 |
|
---|
841 | L<Net::Cmd>
|
---|
842 |
|
---|
843 | =head1 AUTHOR
|
---|
844 |
|
---|
845 | Graham Barr <gbarr@pobox.com>
|
---|
846 |
|
---|
847 | =head1 COPYRIGHT
|
---|
848 |
|
---|
849 | Copyright (c) 1995-2004 Graham Barr. All rights reserved.
|
---|
850 | This program is free software; you can redistribute it and/or modify
|
---|
851 | it under the same terms as Perl itself.
|
---|
852 |
|
---|
853 | =cut
|
---|