File Coverage

blib/lib/neverbounce.pm
Criterion Covered Total %
statement 26 224 11.6
branch 0 88 0.0
condition 0 81 0.0
subroutine 9 19 47.3
pod 0 7 0.0
total 35 419 8.3


line stmt bran cond sub pod time code
1             package neverbounce;
2            
3 1     1   14158 use 5.006;
  1         2  
4 1     1   4 use strict;
  1         2  
  1         16  
5 1     1   2 use warnings;
  1         8  
  1         28  
6 1     1   3 use vars qw($AUTOLOAD $NB_API_VERSION %result_details %status_code_des);
  1         1  
  1         59  
7 1     1   538 use Data::Dumper;
  1         6573  
  1         59  
8 1     1   404 use Convert::Base64;
  1         1056  
  1         45  
9 1     1   426 use HTTP::Request::Common;
  1         16968  
  1         68  
10 1     1   574 use LWP::UserAgent;
  1         14711  
  1         31  
11 1     1   666 use JSON;
  1         8487  
  1         4  
12             require Exporter;
13             $NB_API_VERSION = '3.1';
14             our $VERSION = '0.02';
15             our @ISA = qw(Exporter);
16             our @EXPORT_OK = qw();
17             %result_details = (
18             0 => 'No additional details',
19             1 => 'Provided email failed the syntax check'
20             );
21             %status_code_des= (
22             0 => 'Request has been received but has not started idexing',
23             1 => 'List is indexing and deduping',
24             2 => 'List is awaiting user input (Typically skipped for lists submitted via API)',
25             3 => 'List is being processed',
26             4 => 'List has completed verification',
27             5 => 'List has failed'
28             );
29             sub new {
30 0     0 0   my $class = shift;
31 0           my $self = bless {}, $class;
32 0           my %hash = @_;
33 0           my $temp = $self->_initialize(@_);
34 0 0         if($temp) {
35 0           return $self;
36             } else {
37 0           return;
38             }
39             }
40             sub _initialize {
41 0     0     my $self = shift;
42 0           my %hash = @_;
43 0 0         if (exists($hash{api_username})) {
44 0           $self->{api_username} = $hash{api_username};
45             } else {
46 0           return (resp_status=>'error',data => {error => 'mandatory_value_missing',error_description => "The value for 'api_username' is missing"},request_data => '');
47             }
48 0 0         if (exists($hash{api_secret_key})) {
49 0           $self->{api_secret_key} = $hash{api_secret_key};
50             } else {
51 0           return (resp_status=>'error',data => {error => 'mandatory_value_missing',error_description => "The value for 'api_secret_key' is missing"},request_data => '');
52             }
53 0           $self->{authorization} = encode_base64($self->{api_username}.':'.$self->{api_secret_key});
54 0           my $req;
55 0           $req=POST(
56             "https://api.neverbounce.com/v3/access_token",
57             Content_Type => 'form-data',
58             Content =>[
59             grant_type => 'client_credentials',
60             scope => 'basic user'
61             ]
62             );
63 0           my $ua=LWP::UserAgent->new();
64 0           $ua->ssl_opts( "verify_hostname" => 0 );
65 0           $ua->agent('Mozilla/5.0');
66 0           $ua->default_header("Authorization"=>"Basic ".$self->{authorization});
67 0           my $result=$ua->request($req);
68 0 0 0       if($result->is_success && $result->{_content} ne '') {
69 0           my $response=decode_json($result->{_content});
70 0 0 0       if(defined($response->{error}) || (defined($response->{success}) && $response->{success} ne 1)) {
      0        
71 0           my %response_hash = %{$response};
  0            
72 0           my %error_data = $self->nb_error(%response_hash);
73 0           die Dumper(\%error_data);
74             } else {
75 0           $self->{access_token} = $response->{access_token};
76 0           $self->{expires_in} = $response->{expires_in};
77 0           $self->{token_type} = $response->{token_type};
78 0           $self->{scope} = $response->{scope};
79             }
80             } else {
81 0           my $msg=qq{Processing terminated due to failure in request to neverbounce.com};
82 0 0 0       if($result->is_success && $result->{_content} eq '') {
83 0           $msg=qq{Process terminated since there is no respone data from neverbounce.com};
84 0           print STDERR $msg."\n\n".Dumper($result);
85             } else {
86 0           print STDERR $msg."\n\n".Dumper($result);
87             }
88 0           return 0;
89             }
90             }
91             sub nb_verify_email {
92 0     0 0   my $self = shift;
93 0           my %hash = @_;
94 0 0         if (exists($hash{email})) {
95 0           $self->{email} = $hash{email};
96             } else {
97 0           return (resp_status=>'error',data => {error => 'mandatory_value_missing',error_description => "The value for 'email' is missing. Please provide email address to make verification."},request_data => '');
98             }
99 0           my $req;
100             $req=POST(
101             "https://api.neverbounce.com/v3/single?access_token=".$self->{access_token},
102             Content_Type => 'form-data',
103             Content =>[
104             email => $self->{email}
105 0           ]
106             );
107 0           my $ua=LWP::UserAgent->new();
108 0           $ua->ssl_opts( "verify_hostname" => 0 );
109 0           $ua->agent('Mozilla/5.0');
110 0           my $result=$ua->request($req);
111 0 0 0       if($result->is_success && $result->{_content} ne '') {
112 0           my $response=decode_json($result->{_content});
113 0 0 0       if(defined($response->{error}) || (defined($response->{success}) && $response->{success} ne 1)) {
      0        
114 0           my %response_hash = %{$response};
  0            
115 0           my %error_data = $self->nb_error(%response_hash);
116 0           $error_data{request_data} = Dumper($result);
117 0           return %error_data;
118             } else {
119             my %response_data = (
120             resp_status => 'success',
121             data => {
122             result_code => $response->{result},
123             result_text_code => $self->nb_result_code(result_code=>$response->{result},response_type=>'text_code'),
124             result_description => $self->nb_result_code(result_code=>$response->{result},response_type=>'description'),
125             result_safe_to_send => $self->nb_result_code(result_code=>$response->{result},response_type=>'safe_to_send'),
126             result_details_code => $response->{result_details},
127             result_details_description => $result_details{$response->{result_details}},
128             neverbounce_execution_time => $response->{execution_time}
129             },
130 0           request_data => Dumper($result)
131             );
132 0           return %response_data;
133             }
134             } else {
135 0           my $msg=qq{Processing terminated due to failure in request to neverbounce.com};
136 0 0 0       if($result->is_success && $result->{_content} eq '') {
137 0           $msg=qq{Process terminated since there is no respone data from neverbounce.com};
138             }
139 0           return (resp_status=>'error',data => {error => 'Connection Error',error_description => $msg},request_data => Dumper($result));
140             }
141             }
142             sub nb_email_list_batch_send {
143 0     0 0   my $self = shift;
144 0           my %hash = @_;
145 0 0         $self->{input_location} = ($hash{input_location} eq '1')?$hash{input_location}:'0';
146 0 0         if (exists($hash{input})) {
147 0           $self->{input} = $hash{input};
148             } else {
149 0           return (resp_status=>'error',data => {error => 'mandatory_value_missing',error_description => "The value for 'input' is missing. Expected value: (If 'input_location' = 0, then 'input' should be the URL pointed to file which contain email list. If 'input_location' = 1, then 'input' should be URL encoded string of the contents of email list.)"},request_data => '');
150             }
151 0 0         if (exists($hash{filename})) {
152 0           $self->{filename} = $hash{filename};
153             }
154 0           my $req;
155             $req=POST(
156             "https://api.neverbounce.com/v3/bulk?access_token=".$self->{access_token},
157             Content_Type => 'form-data',
158             Content => [
159             input_location => $self->{input_location},
160             input => $self->{input},
161 0 0         filename => defined($self->{filename})?$self->{filename}:''
162             ]
163             );
164 0           my $ua=LWP::UserAgent->new();
165 0           $ua->ssl_opts( "verify_hostname" => 0 );
166 0           $ua->agent('Mozilla/5.0');
167 0           my $result=$ua->request($req);
168 0 0 0       if($result->is_success && $result->{_content} ne '') {
169 0           my $response=decode_json($result->{_content});
170 0 0 0       if(defined($response->{error}) || (defined($response->{success}) && $response->{success} ne 1)) {
      0        
171 0           my %response_hash = %{$response};
  0            
172 0           my %error_data = $self->nb_error(%response_hash);
173 0           $error_data{request_data} = Dumper($result);
174 0           return %error_data;
175             } else {
176             my %response_data = (
177             resp_status => 'success',
178             data => {
179             job_status => $response->{job_status},
180             job_id => $response->{job_id},
181             neverbounce_execution_time => $response->{execution_time}
182             },
183 0           request_data => Dumper($result)
184             );
185 0           return %response_data;
186             }
187             } else {
188 0           my $msg=qq{Processing terminated due to failure in request to neverbounce.com};
189 0 0 0       if($result->is_success && $result->{_content} eq '') {
190 0           $msg=qq{Process terminated since there is no respone data from neverbounce.com};
191             }
192 0           return (resp_status=>'error',data => {error => 'Connection Error',error_description => $msg},request_data => Dumper($result));
193             }
194             }
195             sub nb_email_list_batch_check {
196 0     0 0   my $self = shift;
197 0           my %hash = @_;
198 0 0         if (exists($hash{job_id})) {
199 0           $self->{job_id} = $hash{job_id};
200             } else {
201 0           return (resp_status=>'error',data => {error => 'mandatory_value_missing',error_description => "The value for 'job_id' is missing."},request_data => '');
202             }
203 0           my $req;
204             $req=POST(
205             "https://api.neverbounce.com/v3/status?access_token=".$self->{access_token},
206             Content_Type => 'form-data',
207             Content =>[
208             version => $NB_API_VERSION,
209             job_id => $self->{job_id}
210 0           ]
211             );
212 0           my $ua=LWP::UserAgent->new();
213 0           $ua->ssl_opts( "verify_hostname" => 0 );
214 0           $ua->agent('Mozilla/5.0');
215 0           my $result=$ua->request($req);
216 0 0 0       if($result->is_success && $result->{_content} ne '') {
217 0           my $response=decode_json($result->{_content});
218 0 0 0       if(defined($response->{error}) || (defined($response->{success}) && $response->{success} ne 1)) {
      0        
219 0           my %response_hash = %{$response};
  0            
220 0           my %error_data = $self->nb_error(%response_hash);
221 0           $error_data{request_data} = Dumper($result);
222 0           return %error_data;
223             } else {
224             my %response_data = (
225             resp_status => 'success',
226             data => {
227             status => $response->{status},
228             status_desc => $status_code_des{$response->{status}},
229             id => $response->{id},
230             type => $response->{type},
231             input_location => $response->{input_location},
232             orig_name => $response->{orig_name},
233             created => $response->{created},
234             started => $response->{started},
235             finished => $response->{finished},
236             file_details => $response->{file_details},
237             job_details => $response->{job_details},
238             neverbounce_execution_time => $response->{execution_time},
239             stats => $response->{stats}
240             },
241 0           request_data => Dumper($result)
242             );
243 0           return %response_data;
244             }
245             } else {
246 0           my $msg=qq{Processing terminated due to failure in request to neverbounce.com};
247 0 0 0       if($result->is_success && $result->{_content} eq '') {
248 0           $msg=qq{Process terminated since there is no respone data from neverbounce.com};
249             }
250 0           return (resp_status=>'error',data => {error => 'Connection Error',error_description => $msg},request_data => Dumper($result));
251             }
252             }
253             sub nb_email_list_batch_result {
254 0     0 0   my $self = shift;
255 0           my %hash = @_;
256 0 0         if (exists($hash{job_id})) {
257 0           $self->{job_id} = $hash{job_id};
258             } else {
259 0           return (resp_status=>'error',data => {error => 'mandatory_value_missing',error_description => "The value for 'job_id' is missing."},request_data => '');
260             }
261 0           my %check_status=$self->nb_email_list_batch_check(job_id=>$hash{job_id});
262 0 0         if($check_status{resp_status} ne 'success'){
    0          
263 0           return %check_status;
264             } elsif($check_status{data}{status} ne '4') {
265             my %error_data = (
266             resp_status=>'error',
267             data => $check_status{data},
268 0           request_data => ''
269             );
270 0           $error_data{data}{error}='list_verification_completion_failure';
271 0           $error_data{data}{error_description}=$check_status{data}{status_desc};
272 0           return %error_data;
273             }
274 0 0         $self->{valids} = ($hash{valids} eq '0')?$hash{valids}:'1';
275 0 0         $self->{invalids} = ($hash{invalids} eq '0')?$hash{invalids}:'1';
276 0 0         $self->{catchall} = ($hash{catchall} eq '0')?$hash{catchall}:'1';
277 0 0         $self->{disposable} = ($hash{disposable} eq '0')?$hash{disposable}:'1';
278 0 0         $self->{unknown} = ($hash{unknown} eq '0')?$hash{unknown}:'1';
279 0 0         $self->{duplicates} = ($hash{duplicates} eq '0')?$hash{duplicates}:'1';
280 0 0         $self->{textcodes} = ($hash{textcodes} eq '0')?$hash{textcodes}:'1';
281 0           my $req;
282             $req=POST(
283             "https://api.neverbounce.com/v3/download?access_token=".$self->{access_token},
284             Content_Type => 'form-data',
285             Content =>[
286             job_id => $self->{job_id},
287             valids => $self->{valids},
288             invalids => $self->{invalids},
289             catchall => $self->{catchall},
290             disposable => $self->{disposable},
291             unknown => $self->{unknown},
292             duplicates => $self->{duplicates},
293             textcodes => $self->{textcodes},
294 0           ]
295             );
296 0           my $ua=LWP::UserAgent->new();
297 0           $ua->ssl_opts( "verify_hostname" => 0 );
298 0           $ua->agent('Mozilla/5.0');
299 0           my $result=$ua->request($req);
300 0           $result->{_content}=~s/\n+$//;
301 0           $result->{_content}=~s/\r+$//;
302 0           $result->{_content}=~s/\n+$//;
303 0 0 0       if($result->is_success && $result->{_content} ne '') {
304 0           my $temp=0;
305 0 0         eval {decode_json($result->{_content});$temp=1;1;} or do {$temp=0;};
  0            
  0            
  0            
  0            
306 0 0         if($temp > 0) {
307 0           my $response=decode_json($result->{_content});
308 0 0 0       if(defined($response->{error}) || (defined($response->{success}) && $response->{success} ne 1)) {
      0        
309 0           my %response_hash = %{$response};
  0            
310 0           my %error_data = $self->nb_error(%response_hash);
311 0           $error_data{request_data} = Dumper($result);
312 0           return %error_data;
313             } else {
314 0           return (resp_status=>'error',data => {error => 'Unknown Error',error_description => "Unknown Error"},request_data => Dumper($result));
315             }
316             } else {
317             my %response_data = (
318             resp_status => 'success',
319             data => {
320             list => $result->{_content}
321             },
322 0           request_data => Dumper($result)
323             );
324 0           return %response_data;
325             }
326             } else {
327 0           my $msg=qq{Processing terminated due to failure in request to neverbounce.com};
328 0 0 0       if($result->is_success && $result->{_content} eq '') {
329 0           $msg=qq{Process terminated since there is no respone data from neverbounce.com};
330             }
331 0           return (resp_status=>'error',data => {error => 'Connection Error',error_description => $msg},request_data => Dumper($result));
332             }
333             }
334             sub nb_result_code {
335 0     0 0   my $self = shift;
336 0           my %hash = @_;
337 0           my %result_codes = (
338             0 => {
339             text_code => 'valid',
340             numeric_code=> '0',
341             description => 'Verified as real address',
342             safe_to_send=> 'Yes'
343             },
344             1 => {
345             text_code => 'invalid',
346             numeric_code=> '1',
347             description => 'Verified as not valid',
348             safe_to_send=> 'No'
349             },
350             2 => {
351             text_code => 'disposable',
352             numeric_code=> '2',
353             description => 'A temporary, disposable address',
354             safe_to_send=> 'No'
355             },
356             3 => {
357             text_code => 'catchall',
358             numeric_code=> '3',
359             description => 'A domain-wide setting',
360             safe_to_send=> 'Maybe. Not recommended unless on private server'
361             },
362             4 => {
363             text_code => 'unknown',
364             numeric_code=> '4',
365             description => 'The server cannot be reached',
366             safe_to_send=> 'No'
367             },
368             'valid' => {
369             text_code => 'valid',
370             numeric_code=> '0',
371             description => 'Verified as real address',
372             safe_to_send=> 'Yes'
373             },
374             'invalid' => {
375             text_code => 'invalid',
376             numeric_code=> '1',
377             description => 'Verified as not valid',
378             safe_to_send=> 'No'
379             },
380             'disposable'=> {
381             text_code => 'disposable',
382             numeric_code=> '2',
383             description => 'A temporary, disposable address',
384             safe_to_send=> 'No'
385             },
386             'catchall' => {
387             text_code => 'catchall',
388             numeric_code=> '3',
389             description => 'A domain-wide setting',
390             safe_to_send=> 'Maybe. Not recommended unless on private server'
391             },
392             'unknown' => {
393             text_code => 'unknown',
394             numeric_code=> '4',
395             description => 'The server cannot be reached',
396             safe_to_send=> 'No'
397             }
398             );
399 0 0 0       if($hash{result_code} && $hash{result_code} ne '' && (($hash{result_code}=~/^\d+$/ && $hash{result_code} < 5) || $hash{result_code} eq 'valid' || $hash{result_code} eq 'invalid' || $hash{result_code} eq 'disposable' || $hash{result_code} eq 'catchall' || $hash{result_code} eq 'unknown')) {
      0        
      0        
400 0 0 0       if($hash{response_type} && $hash{response_type} ne '') {
401 0 0         if(defined($result_codes{$hash{result_code}}{$hash{response_type}})) {
402 0           return $result_codes{$hash{result_code}}{$hash{response_type}};
403             } else {
404 0           return %{$result_codes{$hash{result_code}}};
  0            
405             }
406             } else {
407 0           return %{$result_codes{$hash{result_code}}};
  0            
408             }
409             } else {
410 0           return %result_codes;
411             }
412             }
413             sub nb_error {
414 0     0 0   my $self = shift;
415 0           my %hash = @_;
416 0 0 0       if(defined($hash{'error'})) {
    0          
417 0           return (resp_status=>'error',data => {error => $hash{'error'},error_description => $hash{'error_description'}});
418             } elsif(defined($hash{success}) && $hash{success} ne 'true') {
419 0 0 0       if(defined($hash{msg}) && $hash{msg} ne '') {
420 0 0         if($hash{'msg'} eq "Authentication failed") {
421 0           return (resp_status=>'error',data => {error => 'Expired/Invalid Access Tokens',error_description => $hash{'msg'}});
422             } else {
423 0           return (resp_status=>'error',data => {error => 'API Errors',error_description => $hash{'msg'}});
424             }
425             } else {
426 0           return (resp_status=>'error',data => {error => 'Error Code: '.$hash{'error_code'},error_description => $hash{'error_msg'}});
427             }
428             }
429             }
430             sub AUTOLOAD {
431 0     0     my $self = shift;
432 0   0       my $type = ref($self) || croak("$self is not an object");
433 0           my $field = $AUTOLOAD;
434 0           $field =~ s/.*://;
435 0           my $temp='';
436 0 0         unless (exists $self->{$field}) {
437 0           die "$field does not exist in object/class $type";
438             }
439 0           exit(1);
440             }
441             sub DESTROY {
442 0     0     my $self = undef;
443             }
444             1;
445             __END__