File Coverage

blib/lib/Email/Valid.pm
Criterion Covered Total %
statement 137 199 68.8
branch 63 136 46.3
condition 24 55 43.6
subroutine 22 27 81.4
pod 6 6 100.0
total 252 423 59.5


line stmt bran cond sub pod time code
1             require 5.006;
2 3     3   85696 use strict;
  3         4  
  3         67  
3 3     3   8 use warnings;
  3         2  
  3         179  
4             package Email::Valid;
5             $Email::Valid::VERSION = '1.201';
6             # ABSTRACT: Check validity of Internet email addresses
7             our (
8             $RFC822PAT,
9             $Details, $Resolver, $Nslookup_Path,
10             $Debug,
11             );
12              
13 3     3   9 use Carp;
  3         4  
  3         211  
14 3     3   1162 use IO::File;
  3         13293  
  3         538  
15 3     3   1117 use Mail::Address;
  3         4989  
  3         76  
16 3     3   15 use File::Spec;
  3         4  
  3         60  
17 3     3   12 use Scalar::Util 'blessed';
  3         2  
  3         1519  
18              
19             our %AUTOLOAD = (
20             allow_ip => 1,
21             fqdn => 1,
22             fudge => 1,
23             mxcheck => 1,
24             tldcheck => 1,
25             local_rules => 1,
26             localpart => 1,
27             );
28              
29             our $NSLOOKUP_PAT = 'preference|serial|expire|mail\s+exchanger';
30             our @NSLOOKUP_PATHS = File::Spec->path();
31              
32             # initialize if already loaded, better in prefork mod_perl environment
33             our $DNS_Method = defined $Net::DNS::VERSION ? 'Net::DNS' : '';
34             unless ($DNS_Method) {
35             __PACKAGE__->_select_dns_method;
36             }
37              
38             # initialize $Resolver if necessary
39             if ($DNS_Method eq 'Net::DNS') {
40             unless (defined $Resolver) {
41             $Resolver = Net::DNS::Resolver->new;
42             }
43             }
44              
45             sub new {
46 1     1 1 12 my $class = shift;
47              
48 1   33     6 $class = ref $class || $class;
49 1         3 bless my $self = {}, $class;
50 1         4 $self->_initialize;
51 1         7 %$self = $self->_rearrange([ keys %AUTOLOAD ], \@_);
52 1         5 return $self;
53             }
54              
55             sub _initialize {
56 5     5   5 my $self = shift;
57              
58 5         11 $self->{mxcheck} = 0;
59 5         6 $self->{tldcheck} = 0;
60 5         5 $self->{fudge} = 0;
61 5         4 $self->{fqdn} = 1;
62 5         8 $self->{allow_ip} = 1;
63 5         4 $self->{local_rules} = 0;
64 5         28 $self->{localpart} = 1;
65 5         10 $self->{details} = $Details = undef;
66             }
67              
68             # Pupose: handles named parameter calling style
69             sub _rearrange {
70 68     68   56 my $self = shift;
71 68         55 my(@names) = @{ shift() };
  68         133  
72 68         53 my(@params) = @{ shift() };
  68         79  
73 68         53 my(%args);
74              
75 68 100       258 ref $self ? %args = %$self : _initialize( \%args );
76 68 100       127 return %args unless @params;
77              
78 67 100 66     292 unless (@params > 1 and $params[0] =~ /^-/) {
79 15         27 while(@params) {
80 15 50       20 croak 'unexpected number of parameters' unless @names;
81 15         50 $args{ lc shift @names } = shift @params;
82             }
83 15         71 return %args;
84             }
85              
86 52         84 while(@params) {
87 70         101 my $param = lc substr(shift @params, 1);
88 70         139 $args{ $param } = shift @params;
89             }
90              
91 52         215 %args;
92             }
93              
94             # Purpose: determine why an address failed a check
95             sub details {
96 19     19 1 23 my $self = shift;
97              
98 19 50       42 return (ref $self ? $self->{details} : $Details) unless @_;
    100          
99 16         22 $Details = shift;
100 16 100       37 $self->{details} = $Details if ref $self;
101 16         125 return undef;
102             }
103              
104             # Purpose: Check whether address conforms to RFC 822 syntax.
105             sub rfc822 {
106 31     31 1 26 my $self = shift;
107 31         63 my %args = $self->_rearrange([qw( address )], \@_);
108              
109 31 50       72 my $addr = $args{address} or return $self->details('rfc822');
110 31 50 33     69 $addr = $addr->address if (blessed($addr) && $addr->isa('Mail::Address'));
111              
112 31 100 100     1257 return $self->details('rfc822')
113 3     3   1413 if $addr =~ /\P{ASCII}/ or $addr !~ m/^$RFC822PAT$/o;
  3         27  
  3         42  
114              
115 28         83 return 1;
116             }
117              
118             # Purpose: attempt to locate the nslookup utility
119             sub _find_nslookup {
120 0     0   0 my $self = shift;
121              
122 0         0 my $ns = 'nslookup';
123 0         0 foreach my $path (@NSLOOKUP_PATHS) {
124 0         0 my $file = File::Spec->catfile($path, $ns);
125 0 0 0     0 return "$file.exe" if ($^O eq 'MSWin32') and -x "$file.exe" and !-d _;
      0        
126 0 0 0     0 return $file if -x $file and !-d _;
127             }
128 0         0 return undef;
129             }
130              
131             sub _select_dns_method {
132             # Configure a global resolver object for DNS queries
133             # if Net::DNS is available
134 2     2   2 eval { require Net::DNS };
  2         825  
135 2 50       109751 return $DNS_Method = 'Net::DNS' unless $@;
136              
137 0         0 $DNS_Method = 'nslookup';
138             }
139              
140             # Purpose: perform DNS query using the Net::DNS module
141             sub _net_dns_query {
142 5     5   7 my $self = shift;
143 5         6 my $host = shift;
144              
145 5 50       10 $Resolver = Net::DNS::Resolver->new unless defined $Resolver;
146              
147 5         24 my @mx_entries = Net::DNS::mx($Resolver, $host);
148              
149             # Check for valid MX records for $host
150 5 100       428160 if (@mx_entries) {
151 2         5 foreach my $mx (@mx_entries) {
152 2         7 my $mxhost = $mx->exchange;
153 2         132 my $query = $Resolver->search($mxhost);
154 2 50       7638 next unless ($query);
155 2         7 foreach my $a_rr ($query->answer) {
156 2 50       16 return 1 unless $a_rr->type ne 'A';
157             }
158             }
159             }
160              
161             # Chceck for A record for $host
162 3         14 my @a_rrs = Net::DNS::rr($Resolver, $host, 'A');
163 3 50       121873 if (@a_rrs) {
164 0         0 foreach my $a_rr (@a_rrs) {
165 0 0       0 return 1 unless $a_rr->type ne 'A';
166             }
167             }
168              
169             # MX Check failed
170 3         20 return $self->details('mx');
171             }
172              
173             # Purpose: perform DNS query using the nslookup utility
174             sub _nslookup_query {
175 0     0   0 my $self = shift;
176 0         0 my $host = shift;
177 0         0 local($/, *OLDERR);
178              
179 0 0       0 unless ($Nslookup_Path) {
180 0 0       0 $Nslookup_Path = $self->_find_nslookup
181             or croak 'unable to locate nslookup';
182             }
183              
184             # Check for an A record
185 0 0       0 return 1 if gethostbyname $host;
186              
187             # Check for an MX record
188 0 0 0     0 if ($^O eq 'MSWin32' or $^O eq 'Cygwin') {
189             # Oh no, we're on Windows!
190 0         0 require IO::CaptureOutput;
191 0         0 my $response = IO::CaptureOutput::capture_exec(
192             $Nslookup_Path, '-query=mx', $host
193             );
194 0 0       0 croak "unable to execute nslookup '$Nslookup_Path': exit $?" if $?;
195 0 0       0 print STDERR $response if $Debug;
196 0 0       0 $response =~ /$NSLOOKUP_PAT/io or return $self->details('mx');
197 0         0 return 1;
198             } else {
199             # phew, we're not on Windows!
200 0 0       0 if (my $fh = IO::File->new('-|')) {
201 0         0 my $response = <$fh>;
202 0 0       0 print STDERR $response if $Debug;
203 0         0 close $fh;
204 0 0       0 $response =~ /$NSLOOKUP_PAT/io or return $self->details('mx');
205 0         0 return 1;
206             } else {
207 0 0       0 open OLDERR, '>&STDERR' or croak "cannot dup stderr: $!";
208 0 0       0 open STDERR, '>&STDOUT' or croak "cannot redirect stderr to stdout: $!";
209             {
210 0         0 exec $Nslookup_Path, '-query=mx', $host;
  0         0  
211             }
212 0         0 open STDERR, ">&OLDERR";
213 0         0 croak "unable to execute nslookup '$Nslookup_Path': $!";
214             }
215             }
216             }
217              
218             # Purpose: Check whether a top level domain is valid for a domain.
219             sub tld {
220 0     0 1 0 my $self = shift;
221 0         0 my %args = $self->_rearrange([qw( address )], \@_);
222              
223 0 0       0 unless (eval {require Net::Domain::TLD; Net::Domain::TLD->VERSION(1.65); 1}) {
  0         0  
  0         0  
  0         0  
224 0         0 die "Net::Domain::TLD not available";
225             }
226              
227 0   0     0 my $host = $self->_host( $args{address} or return $self->details('tld') );
228 0         0 my ($tld) = $host =~ m#\.(\w+)$#;
229              
230 0         0 my %invalid_tlds = map { $_ => 1 } qw(invalid test example localhost);
  0         0  
231              
232 0 0       0 return defined $invalid_tlds{$tld} ? 0 : Net::Domain::TLD::tld_exists($tld);
233             }
234              
235             # Purpose: Check whether a DNS record (A or MX) exists for a domain.
236             sub mx {
237 5     5 1 40 my $self = shift;
238 5         16 my %args = $self->_rearrange([qw( address )], \@_);
239              
240 5 50       19 my $host = $self->_host($args{address}) or return $self->details('mx');
241              
242 5 50       10 $self->_select_dns_method unless $DNS_Method;
243              
244 5 50       13 if ($DNS_Method eq 'Net::DNS') {
    0          
245 5 50       12 print STDERR "using Net::DNS for dns query\n" if $Debug;
246 5         14 return $self->_net_dns_query( $host );
247             } elsif ($DNS_Method eq 'nslookup') {
248 0 0       0 print STDERR "using nslookup for dns query\n" if $Debug;
249 0         0 return $self->_nslookup_query( $host );
250             } else {
251 0         0 croak "unknown DNS method '$DNS_Method'";
252             }
253             }
254              
255             # Purpose: convert address to host
256             # Returns: host
257              
258             sub _host {
259 5     5   7 my $self = shift;
260 5         8 my $addr = shift;
261              
262 5 50 33     15 $addr = $addr->address if (blessed($addr) && $addr->isa('Mail::Address'));
263              
264 5 50       17 my $host = ($addr =~ /^.*@(.*)$/ ? $1 : $addr);
265 5         10 $host =~ s/\s+//g;
266              
267             # REMOVE BRACKETS IF IT'S A DOMAIN-LITERAL
268             # RFC822 3.4.6
269             # Square brackets ("[" and "]") are used to indicate the
270             # presence of a domain-literal, which the appropriate
271             # name-domain is to use directly, bypassing normal
272             # name-resolution mechanisms.
273 5         25 $host =~ s/(^\[)|(\]$)//g;
274 5         11 $host;
275             }
276              
277             # Purpose: Fix common addressing errors
278             # Returns: Possibly modified address
279             sub _fudge {
280 1     1   1 my $self = shift;
281 1         2 my $addr = shift;
282              
283 1 50       7 $addr =~ s/\s+//g if $addr =~ /aol\.com$/i;
284 1 50       3 $addr =~ s/,/./g if $addr =~ /compuserve\.com$/i;
285 1         2 $addr;
286             }
287              
288             # Purpose: Special address restrictions on a per-domain basis.
289             # Caveats: These organizations may change their rules at any time.
290             sub _local_rules {
291 0     0   0 my $self = shift;
292 0         0 my($user, $host) = @_;
293              
294 0         0 1;
295             }
296              
297             sub _valid_local_part {
298 27     27   205 my ($self, $localpart) = @_;
299              
300 27 100 66     101 return 0 unless defined $localpart and length $localpart <= 64;
301              
302 26         55 return 1;
303             }
304              
305             sub _valid_domain_parts {
306 24     24   152 my ($self, $string) = @_;
307              
308 24 50 33     75 return unless $string and length $string <= 255;
309 24 50       43 return if $string =~ /\.\./;
310 24         57 my @labels = split /\./, $string;
311              
312 24         33 for my $label (@labels) {
313 51 100       62 return 0 unless $self->_is_domain_label($label);
314             }
315 21         26 return scalar @labels;
316             }
317              
318             sub _is_domain_label {
319 51     51   43 my ($self, $string) = @_;
320 51 100       144 return unless $string =~ /\A
321             [A-Z0-9] # must start with an alnum
322             (?:
323             [-A-Z0-9]* # then maybe a dash or alnum
324             [A-Z0-9] # finally ending with an alnum
325             )? # lather, rinse, repeat
326             \z/ix;
327 48         83 return 1;
328             }
329              
330             # Purpose: Put an address through a series of checks to determine
331             # whether it should be considered valid.
332             sub address {
333 31     31 1 3779 my $self = shift;
334 31         113 my %args = $self->_rearrange([qw( address fudge mxcheck tldcheck fqdn
335             local_rules )], \@_);
336              
337 31 50       89 my $addr = $args{address} or return $self->details('rfc822');
338 31 100 66     117 $addr = $addr->address if (blessed($addr) && $addr->isa('Mail::Address'));
339              
340 31 100       67 $addr = $self->_fudge( $addr ) if $args{fudge};
341 31 100       77 $self->rfc822( -address => $addr ) or return undef;
342              
343 28         124 ($addr) = Mail::Address->parse( $addr );
344              
345 28 50       3128 $addr or return $self->details('rfc822'); # This should never happen
346              
347 28 100       54 if (length($addr->address) > 254) {
348 1         7 return $self->details('address_too_long');
349             }
350              
351 27 50       172 if ($args{local_rules}) {
352 0 0       0 $self->_local_rules( $addr->user, $addr->host )
353             or return $self->details('local_rules');
354             }
355              
356 27 50       53 if ($args{localpart}) {
357 27 100       56 $self->_valid_local_part($addr->user) > 0
358             or return $self->details('localpart');
359             }
360              
361 26   100     76 my $ip_ok = $args{allow_ip} && $addr->host =~ /\A\[
362             (?:[0-9]{1,3}\.){3}[0-9]{1,3}
363             /x;
364              
365 26 100 66     261 if (! $ip_ok && $args{fqdn}) {
366 24         38 my $domain_parts = $self->_valid_domain_parts($addr->host);
367              
368 24 100 100     107 return $self->details('fqdn')
      33        
369             unless $ip_ok || ($domain_parts && $domain_parts > 1);
370             }
371              
372 21 50 66     57 if (! $ip_ok && $args{tldcheck}) {
373 0 0       0 $self->tld( $addr->host ) or return $self->details('tldcheck');
374             }
375              
376 21 100       29 if ($args{mxcheck}) {
377             # I'm not sure this ->details call is needed, but I'll test for it later.
378             # The whole ->details thing is... weird. -- rjbs, 2006-06-08
379 5 100       11 $self->mx( $addr->host ) or return $self->details('mxcheck');
380             }
381              
382 18 50       99 return (wantarray ? ($addr->address, $addr) : $addr->address);
383             }
384              
385             sub AUTOLOAD {
386 0     0     my $self = shift;
387 0   0       my $type = ref($self) || die "$self is not an object";
388 0           my $name = our $AUTOLOAD;
389              
390 0           $name =~ s/.*://;
391 0 0         return if $name eq 'DESTROY';
392 0 0         die "unknown autoload name '$name'" unless $AUTOLOAD{$name};
393              
394 0 0         return (@_ ? $self->{$name} = shift : $self->{$name});
395             }
396              
397             # Regular expression built using Jeffrey Friedl's example in
398             # _Mastering Regular Expressions_ (http://www.ora.com/catalog/regexp/).
399              
400             $RFC822PAT = <<'EOF';
401             [\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\
402             xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xf
403             f\n\015()]*)*\)[\040\t]*)*(?:(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\x
404             ff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|"[^\\\x80-\xff\n\015
405             "]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015"]*)*")[\040\t]*(?:\([^\\\x80-\
406             xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80
407             -\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*
408             )*(?:\.[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\
409             \\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\
410             x80-\xff\n\015()]*)*\)[\040\t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x8
411             0-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|"[^\\\x80-\xff\n
412             \015"]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015"]*)*")[\040\t]*(?:\([^\\\x
413             80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^
414             \x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040
415             \t]*)*)*@[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([
416             ^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\
417             \\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\
418             x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|\[(?:[^\\\x80-
419             \xff\n\015\[\]]|\\[^\x80-\xff])*\])[\040\t]*(?:\([^\\\x80-\xff\n\015()
420             ]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\
421             x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:\.[\04
422             0\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\
423             n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\
424             015()]*)*\)[\040\t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?!
425             [^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|\[(?:[^\\\x80-\xff\n\015\[\
426             ]]|\\[^\x80-\xff])*\])[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\
427             x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\01
428             5()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*)*|(?:[^(\040)<>@,;:".
429             \\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]
430             )|"[^\\\x80-\xff\n\015"]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015"]*)*")[^
431             ()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037]*(?:(?:\([^\\\x80-\xff\n\0
432             15()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][
433             ^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)|"[^\\\x80-\xff\
434             n\015"]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015"]*)*")[^()<>@,;:".\\\[\]\
435             x80-\xff\000-\010\012-\037]*)*<[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?
436             :(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-
437             \xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:@[\040\t]*
438             (?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015
439             ()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()
440             ]*)*\)[\040\t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\0
441             40)<>@,;:".\\\[\]\000-\037\x80-\xff])|\[(?:[^\\\x80-\xff\n\015\[\]]|\\
442             [^\x80-\xff])*\])[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\
443             xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*
444             )*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:\.[\040\t]*(?:\([^\\\x80
445             -\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x
446             80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t
447             ]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\
448             \[\]\000-\037\x80-\xff])|\[(?:[^\\\x80-\xff\n\015\[\]]|\\[^\x80-\xff])
449             *\])[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x
450             80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80
451             -\xff\n\015()]*)*\)[\040\t]*)*)*(?:,[\040\t]*(?:\([^\\\x80-\xff\n\015(
452             )]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\
453             \x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*@[\040\t
454             ]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\0
455             15()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015
456             ()]*)*\)[\040\t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(
457             \040)<>@,;:".\\\[\]\000-\037\x80-\xff])|\[(?:[^\\\x80-\xff\n\015\[\]]|
458             \\[^\x80-\xff])*\])[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80
459             -\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()
460             ]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:\.[\040\t]*(?:\([^\\\x
461             80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^
462             \x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040
463             \t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".
464             \\\[\]\000-\037\x80-\xff])|\[(?:[^\\\x80-\xff\n\015\[\]]|\\[^\x80-\xff
465             ])*\])[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\
466             \x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x
467             80-\xff\n\015()]*)*\)[\040\t]*)*)*)*:[\040\t]*(?:\([^\\\x80-\xff\n\015
468             ()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\
469             \\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*)?(?:[^
470             (\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-
471             \037\x80-\xff])|"[^\\\x80-\xff\n\015"]*(?:\\[^\x80-\xff][^\\\x80-\xff\
472             n\015"]*)*")[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|
473             \([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))
474             [^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:\.[\040\t]*(?:\([^\\\x80-\xff
475             \n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\x
476             ff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(
477             ?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\
478             000-\037\x80-\xff])|"[^\\\x80-\xff\n\015"]*(?:\\[^\x80-\xff][^\\\x80-\
479             xff\n\015"]*)*")[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\x
480             ff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)
481             *\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*)*@[\040\t]*(?:\([^\\\x80-\x
482             ff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-
483             \xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)
484             *(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\
485             ]\000-\037\x80-\xff])|\[(?:[^\\\x80-\xff\n\015\[\]]|\\[^\x80-\xff])*\]
486             )[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-
487             \xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\x
488             ff\n\015()]*)*\)[\040\t]*)*(?:\.[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(
489             ?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80
490             -\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:[^(\040)<
491             >@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x8
492             0-\xff])|\[(?:[^\\\x80-\xff\n\015\[\]]|\\[^\x80-\xff])*\])[\040\t]*(?:
493             \([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]
494             *(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)
495             *\)[\040\t]*)*)*>)
496             EOF
497              
498             $RFC822PAT =~ s/\n//g;
499              
500             1;
501              
502              
503             #pod =head1 SYNOPSIS
504             #pod
505             #pod use Email::Valid;
506             #pod my $address = Email::Valid->address('maurice@hevanet.com');
507             #pod print ($address ? 'yes' : 'no');
508             #pod
509             #pod =head1 DESCRIPTION
510             #pod
511             #pod This module determines whether an email address is well-formed, and
512             #pod optionally, whether a mail host exists for the domain.
513             #pod
514             #pod Please note that there is no way to determine whether an
515             #pod address is deliverable without attempting delivery
516             #pod (for details, see L).
517             #pod
518             #pod =head1 PREREQUISITES
519             #pod
520             #pod This module requires perl 5.004 or later and the L module.
521             #pod Either the L module or the nslookup utility is required
522             #pod for DNS checks. The L module is required to check the
523             #pod validity of top level domains.
524             #pod
525             #pod =head1 METHODS
526             #pod
527             #pod Every method which accepts an C<<
>> parameter may
528             #pod be passed either a string or an instance of the Mail::Address
529             #pod class. All errors raise an exception.
530             #pod
531             #pod =over 4
532             #pod
533             #pod =item new ( [PARAMS] )
534             #pod
535             #pod This method is used to construct an Email::Valid object.
536             #pod It accepts an optional list of named parameters to
537             #pod control the behavior of the object at instantiation.
538             #pod
539             #pod The following named parameters are allowed. See the
540             #pod individual methods below for details.
541             #pod
542             #pod -mxcheck
543             #pod -tldcheck
544             #pod -fudge
545             #pod -fqdn
546             #pod -allow_ip
547             #pod -local_rules
548             #pod
549             #pod =item mx (
| )
550             #pod
551             #pod This method accepts an email address or domain name and determines
552             #pod whether a DNS record (A or MX) exists for it.
553             #pod
554             #pod The method returns true if a record is found and undef if not.
555             #pod
556             #pod Either the Net::DNS module or the nslookup utility is required for
557             #pod DNS checks. Using Net::DNS is the preferred method since error
558             #pod handling is improved. If Net::DNS is available, you can modify
559             #pod the behavior of the resolver (e.g. change the default tcp_timeout
560             #pod value) by manipulating the global L instance stored in
561             #pod C<$Email::Valid::Resolver>.
562             #pod
563             #pod =item rfc822 (
)
564             #pod
565             #pod This method determines whether an address conforms to the RFC822
566             #pod specification (except for nested comments). It returns true if it
567             #pod conforms and undef if not.
568             #pod
569             #pod =item fudge ( | )
570             #pod
571             #pod Specifies whether calls to address() should attempt to correct
572             #pod common addressing errors. Currently, this results in the removal of
573             #pod spaces in AOL addresses, and the conversion of commas to periods in
574             #pod Compuserve addresses. The default is false.
575             #pod
576             #pod =item allow_ip ( | )
577             #pod
578             #pod Specifies whether a "domain literal" is acceptable as the domain part. That
579             #pod means addresses like: C
580             #pod
581             #pod The checking for the domain literal is stricter than the RFC and looser than
582             #pod checking for a valid IP address, I.
583             #pod
584             #pod The default is true.
585             #pod
586             #pod =item fqdn ( | )
587             #pod
588             #pod Specifies whether addresses passed to address() must contain a fully
589             #pod qualified domain name (FQDN). The default is true.
590             #pod
591             #pod B FQDN checks only occur for non-domain-literals. In other
592             #pod words, if you have set C and the address ends in a bracketed IP
593             #pod address, the FQDN check will not occur.
594             #pod
595             #pod =item tld (
)
596             #pod
597             #pod This method determines whether the domain part of an address is in a
598             #pod recognized top-level domain.
599             #pod
600             #pod B TLD checks only occur for non-domain-literals. In other
601             #pod words, if you have set C and the address ends in a bracketed IP
602             #pod address, the TLD check will not occur.
603             #pod
604             #pod =item local_rules ( | )
605             #pod
606             #pod Specifies whether addresses passed to address() should be tested
607             #pod for domain specific restrictions. Currently, this is limited to
608             #pod certain AOL restrictions that I'm aware of. The default is false.
609             #pod
610             #pod =item mxcheck ( | )
611             #pod
612             #pod Specifies whether addresses passed to address() should be checked
613             #pod for a valid DNS entry. The default is false.
614             #pod
615             #pod =item tldcheck ( | )
616             #pod
617             #pod Specifies whether addresses passed to address() should be checked
618             #pod for a valid top level domains. The default is false.
619             #pod
620             #pod =item address (
)
621             #pod
622             #pod This is the primary method which determines whether an email
623             #pod address is valid. Its behavior is modified by the values of
624             #pod mxcheck(), tldcheck(), local_rules(), fqdn(), and fudge(). If the address
625             #pod passes all checks, the (possibly modified) address is returned as
626             #pod a string. Otherwise, undef is returned.
627             #pod In a list context, the method also returns an instance of the
628             #pod Mail::Address class representing the email address.
629             #pod
630             #pod =item details ()
631             #pod
632             #pod If the last call to address() returned undef, you can call this
633             #pod method to determine why it failed. Possible values are:
634             #pod
635             #pod rfc822
636             #pod localpart
637             #pod local_rules
638             #pod fqdn
639             #pod mxcheck
640             #pod tldcheck
641             #pod
642             #pod If the class is not instantiated, you can get the same information
643             #pod from the global C<$Email::Valid::Details>.
644             #pod
645             #pod =back
646             #pod
647             #pod =head1 EXAMPLES
648             #pod
649             #pod Let's see if the address 'maurice@hevanet.com' conforms to the
650             #pod RFC822 specification:
651             #pod
652             #pod print (Email::Valid->address('maurice@hevanet.com') ? 'yes' : 'no');
653             #pod
654             #pod Additionally, let's make sure there's a mail host for it:
655             #pod
656             #pod print (Email::Valid->address( -address => 'maurice@hevanet.com',
657             #pod -mxcheck => 1 ) ? 'yes' : 'no');
658             #pod
659             #pod Let's see an example of how the address may be modified:
660             #pod
661             #pod $addr = Email::Valid->address('Alfred Neuman ');
662             #pod print "$addr\n"; # prints Neuman@foo.bar
663             #pod
664             #pod Now let's add the check for top level domains:
665             #pod
666             #pod $addr = Email::Valid->address( -address => 'Neuman@foo.bar',
667             #pod -tldcheck => 1 );
668             #pod print "$addr\n"; # doesn't print anything
669             #pod
670             #pod Need to determine why an address failed?
671             #pod
672             #pod unless(Email::Valid->address('maurice@hevanet')) {
673             #pod print "address failed $Email::Valid::Details check.\n";
674             #pod }
675             #pod
676             #pod If an error is encountered, an exception is raised. This is really
677             #pod only possible when performing DNS queries. Trap any exceptions by
678             #pod wrapping the call in an eval block:
679             #pod
680             #pod eval {
681             #pod $addr = Email::Valid->address( -address => 'maurice@hevanet.com',
682             #pod -mxcheck => 1 );
683             #pod };
684             #pod warn "an error was encountered: $@" if $@;
685             #pod
686             #pod =head1 CREDITS
687             #pod
688             #pod Significant portions of this module are based on the ckaddr program
689             #pod written by Tom Christiansen and the RFC822 address pattern developed
690             #pod by Jeffrey Friedl. Neither were involved in the construction of this
691             #pod module; all errors are mine.
692             #pod
693             #pod Thanks very much to the following people for their suggestions and
694             #pod bug fixes:
695             #pod
696             #pod Otis Gospodnetic
697             #pod Kim Ryan
698             #pod Pete Ehlke
699             #pod Lupe Christoph
700             #pod David Birnbaum
701             #pod Achim
702             #pod Elizabeth Mattijsen (liz@dijkmat.nl)
703             #pod
704             #pod =head1 SEE ALSO
705             #pod
706             #pod L, L, L, L
707             #pod
708             #pod L -
709             #pod standard for the format of ARPA internet text messages.
710             #pod Superseded by L.
711             #pod
712             #pod =cut
713              
714             __END__