zerobounce-sdk 1.1.2 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1d0e54bfd6db4f61595d1ca91ea16090f9a4c3d31a167bbab38bda3b6760155d
4
- data.tar.gz: c05b9b9f3b680019d8bac6deddba297b0ba6d2708856fa01fab0038cdff89435
3
+ metadata.gz: 05ca50ba9671572511cbd49f67ab96fd7b2956e7143ccbcc03e4a53daaed8601
4
+ data.tar.gz: 863f281ff04f36fc68b7d87468056c58ceff7426318c86f6c4030bfd3f036b29
5
5
  SHA512:
6
- metadata.gz: d9a308aca4d26a7a28b6a15d6cde4735c8955c28e1210b23a2fe86779261ac726ebfc418d19b228caff7c37dd09e058e3f86b35bb533434b7aadfd52b7d421b6
7
- data.tar.gz: e9512073456e588ac04c14f8ee07dc8b84eae890031cc6ac2adc4766da1b80adce69e6a60112144e72d7561942f6c32674347a1ad24ab11b15ed2622b3b8d071
6
+ metadata.gz: 0577e5dbe7e0d013efc8da85ba6691df0adc88c5e519be4453696f40b14fb89374b7afcdd20ef053ceeff287965a3f3639489cc84752407ca6540e8a0ec1af91
7
+ data.tar.gz: c5d789f36349693e1a5dce55db8613e4ccd9017864ec7617bedb837cb5d36f049b4387163183773282abc45e4c451eb53aa85119f99ea0bd549e95eeff2f4241
data/.env.sample CHANGED
@@ -1,3 +1,5 @@
1
1
  ZEROBOUNCE_API_KEY=99e7ef20ceea4480a173b07b1be75371
2
2
  INCORRECT_API_KEY=thiskeyisinvalidorotherwiseincorrect
3
- TEST=unit
3
+
4
+ ZEROBOUNCE_API_URL=https://api.zerobounce.net/v2
5
+ ZEROBOUNCE_BULK_API_URL=https://bulkapi.zerobounce.net/v2
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- zerobounce-sdk (1.1.1)
4
+ zerobounce-sdk (1.2.0)
5
5
  dotenv
6
6
  rest-client (~> 2.1)
7
7
 
data/README.md CHANGED
@@ -23,19 +23,128 @@ Import
23
23
  require 'zerobounce'
24
24
  ```
25
25
 
26
- Set a valid ZeroBounce API key.
26
+ ## Configuration
27
+
28
+ ### Setting API Key
29
+
30
+ #### Method 1: Using configure block (recommended)
27
31
  ```ruby
28
32
  Zerobounce.configure do |config|
29
33
  config.apikey = '<zerobounce-api-key>'
30
- ...
34
+ # Optional: Set custom API URLs
35
+ config.api_root_url = 'https://api.zerobounce.net/v2'
36
+ config.bulk_api_root_url = 'https://bulkapi.zerobounce.net/v2'
31
37
  end
32
38
  ```
33
- or
39
+
40
+ #### Method 1a: Using ApiUrls constants (convenience)
41
+ ```ruby
42
+ # Global API (default)
43
+ Zerobounce.configure do |config|
44
+ config.apikey = '<zerobounce-api-key>'
45
+ config.api_root_url = Zerobounce::ApiUrls::DEFAULT_URL
46
+ config.bulk_api_root_url = Zerobounce::ApiUrls::BULK_DEFAULT_URL
47
+ end
48
+
49
+ # European API (convenience)
50
+ Zerobounce.configure do |config|
51
+ config.apikey = '<zerobounce-api-key>'
52
+ config.api_root_url = Zerobounce::ApiUrls::EU_URL
53
+ config.bulk_api_root_url = Zerobounce::ApiUrls::BULK_DEFAULT_URL
54
+ end
55
+
56
+ # US API (convenience)
57
+ Zerobounce.configure do |config|
58
+ config.apikey = '<zerobounce-api-key>'
59
+ config.api_root_url = Zerobounce::ApiUrls::US_URL
60
+ config.bulk_api_root_url = Zerobounce::ApiUrls::BULK_DEFAULT_URL
61
+ end
34
62
  ```
63
+
64
+ #### Method 2: Direct configuration
65
+ ```ruby
35
66
  Zerobounce.config.apikey = '<zerobounce-api-key>'
36
- ...
67
+ # Optional: Set custom API URLs
68
+ Zerobounce.config.api_root_url = 'https://api.zerobounce.net/v2'
69
+ Zerobounce.config.bulk_api_root_url = 'https://bulkapi.zerobounce.net/v2'
70
+ ```
71
+
72
+ #### Method 3: Using environment variables
73
+ Create a `.env` file in your project root:
74
+ ```bash
75
+ ZEROBOUNCE_API_KEY=your_api_key_here
76
+ ZEROBOUNCE_API_URL=https://api.zerobounce.net/v2
77
+ ZEROBOUNCE_BULK_API_URL=https://bulkapi.zerobounce.net/v2
78
+ ```
79
+
80
+ The gem will automatically load these environment variables when initialized. No additional configuration needed in your code.
81
+
82
+ #### Method 4: System environment variables
83
+ Set environment variables in your system:
84
+ ```bash
85
+ export ZEROBOUNCE_API_KEY=your_api_key_here
86
+ export ZEROBOUNCE_API_URL=https://api.zerobounce.net/v2
87
+ export ZEROBOUNCE_BULK_API_URL=https://bulkapi.zerobounce.net/v2
88
+ ```
89
+
90
+
91
+ ### API URL Configuration Details
92
+
93
+ #### Default Behavior
94
+ If you don't specify `api_root_url` or `bulk_api_root_url`, the gem will use the following defaults:
95
+ - **Main API**: `https://api.zerobounce.net/v2`
96
+ - **Bulk API**: `https://bulkapi.zerobounce.net/v2`
97
+
98
+ These defaults are defined in the `Zerobounce::ApiUrls` class constants:
99
+ - `Zerobounce::ApiUrls::DEFAULT_URL` - Main API URL (Global)
100
+ - `Zerobounce::ApiUrls::EU_URL` - European API URL
101
+ - `Zerobounce::ApiUrls::US_URL` - US API URL
102
+ - `Zerobounce::ApiUrls::BULK_DEFAULT_URL` - Bulk API URL
103
+
104
+ #### Using ApiUrls Constants
105
+ You can use the predefined constants in your configuration. The EU and US URLs are provided as convenience options:
106
+
107
+ ```ruby
108
+ # Global API (default)
109
+ Zerobounce.configure do |config|
110
+ config.apikey = 'your-api-key'
111
+ config.api_root_url = Zerobounce::ApiUrls::DEFAULT_URL
112
+ config.bulk_api_root_url = Zerobounce::ApiUrls::BULK_DEFAULT_URL
113
+ end
114
+
115
+ # European API
116
+ Zerobounce.configure do |config|
117
+ config.apikey = 'your-api-key'
118
+ config.api_root_url = Zerobounce::ApiUrls::EU_URL
119
+ config.bulk_api_root_url = Zerobounce::ApiUrls::BULK_DEFAULT_URL
120
+ end
121
+
122
+ # US API
123
+ Zerobounce.configure do |config|
124
+ config.apikey = 'your-api-key'
125
+ config.api_root_url = Zerobounce::ApiUrls::US_URL
126
+ config.bulk_api_root_url = Zerobounce::ApiUrls::BULK_DEFAULT_URL
127
+ end
37
128
  ```
38
129
 
130
+ #### Custom API URLs
131
+ You can override the default URLs for custom deployments or testing:
132
+
133
+ ```ruby
134
+ Zerobounce.configure do |config|
135
+ config.apikey = 'your-api-key'
136
+ # Use custom URLs (e.g., for testing or custom deployments)
137
+ config.api_root_url = 'https://custom-api.example.com/v2'
138
+ config.bulk_api_root_url = 'https://custom-bulk-api.example.com/v2'
139
+ end
140
+ ```
141
+
142
+ #### Environment Variable Priority
143
+ The configuration follows this priority order (highest to lowest):
144
+ 1. Explicitly set in code (`config.api_root_url = '...'`)
145
+ 2. Environment variables (`ZEROBOUNCE_API_URL`, `ZEROBOUNCE_BULK_API_URL`)
146
+ 3. Default constants (`ApiUrls::DEFAULT_URL`, `ApiUrls::BULK_DEFAULT_URL`)
147
+
39
148
  Credits
40
149
  ```ruby
41
150
  Zerobounce.credits
@@ -412,9 +521,10 @@ When `has_header_row: false` is provided to `scoring_file_send()` method, column
412
521
 
413
522
  ### Email Finder
414
523
 
415
- Guess Format
524
+ Guess Format by Domain
416
525
  ```ruby
417
- Zerobounce.guessformat("zerobounce.net")
526
+ # New keyword argument syntax (recommended)
527
+ Zerobounce.guessformat(domain: "zerobounce.net")
418
528
  =>
419
529
  {"email"=>"",
420
530
  "domain"=>"zerobounce.net",
@@ -451,21 +561,158 @@ Zerobounce.guessformat("zerobounce.net")
451
561
  {"format"=>"lastf", "confidence"=>"medium"},
452
562
  {"format"=>"l-first", "confidence"=>"low"},
453
563
  {"format"=>"l_first", "confidence"=>"low"}]}
454
- # Zerobounce.guessformat("zerobounce.net", first_name: "John", middle_name: 'Deere', last_name: "Doe")
564
+
565
+ # With names for better accuracy (new syntax)
566
+ Zerobounce.guessformat(domain: "zerobounce.net", first_name: "John", middle_name: 'Deere', last_name: "Doe")
567
+
568
+ # Backwards compatible syntax (still supported)
569
+ Zerobounce.guessformat("zerobounce.net")
570
+ Zerobounce.guessformat("zerobounce.net", first_name: "John", middle_name: 'Deere', last_name: "Doe")
571
+ ```
572
+
573
+ Guess Format by Company Name
574
+ ```ruby
575
+ # New keyword argument syntax (recommended)
576
+ Zerobounce.guessformat(company_name: "Zero Bounce")
577
+ =>
578
+ {"email"=>"",
579
+ "company_name"=>"Zero Bounce",
580
+ "format"=>"first.last",
581
+ "status"=>"",
582
+ "sub_status"=>"",
583
+ "confidence"=>"high",
584
+ "did_you_mean"=>"",
585
+ "failure_reason"=>"",
586
+ "other_domain_formats"=>[...]}
587
+
588
+ # With names for better accuracy (new syntax)
589
+ Zerobounce.guessformat(first_name: "John", last_name: "Doe", company_name: "Zero Bounce")
590
+ ```
591
+
592
+ Find Email Address
593
+ ```ruby
594
+ # Find email by domain
595
+ Zerobounce.find_email("John", domain: "zerobounce.net")
596
+ =>
597
+ {
598
+ "email": "john@zerobounce.net",
599
+ "email_confidence": "medium",
600
+ "domain": "zerobounce.net",
601
+ "company_name": "ZeroBounce",
602
+ "did_you_mean": "",
603
+ "failure_reason": ""
604
+ }
605
+
606
+ # Find email by company name
607
+ Zerobounce.find_email("John", company_name: "Zero Bounce")
608
+ =>
609
+ {
610
+ "email": "john@zerobounce.net",
611
+ "email_confidence": "medium",
612
+ "domain": "zerobounce.net",
613
+ "company_name": "ZeroBounce",
614
+ "did_you_mean": "",
615
+ "failure_reason": ""
616
+ }
617
+
618
+ # With additional name information for better accuracy
619
+ Zerobounce.find_email("John", domain: "zerobounce.net", middle_name: "Deere", last_name: "Doe")
620
+ ```
621
+
622
+ Find Domain Information
623
+ ```ruby
624
+ # Find domain format by domain
625
+ Zerobounce.find_domain(domain: "zerobounce.net")
626
+ =>
627
+ {
628
+ "domain": "zerobounce.net",
629
+ "company_name": "Hertza, LLC",
630
+ "format": "first.last",
631
+ "confidence": "high",
632
+ "did_you_mean": "",
633
+ "failure_reason": "",
634
+ "other_domain_formats": [
635
+ {"format": "first", "confidence": "high"},
636
+ {"format": "last.first", "confidence": "high"},
637
+ {"format": "lastfirst", "confidence": "high"},
638
+ {"format": "firstl", "confidence": "high"},
639
+ {"format": "lfirst", "confidence": "high"},
640
+ {"format": "firstlast", "confidence": "high"},
641
+ {"format": "last_middle_f", "confidence": "high"},
642
+ {"format": "last", "confidence": "high"},
643
+ {"format": "f.last", "confidence": "medium"},
644
+ {"format": "last-f", "confidence": "medium"},
645
+ {"format": "l.first", "confidence": "medium"},
646
+ {"format": "last_f", "confidence": "medium"},
647
+ {"format": "first.middle.last", "confidence": "medium"},
648
+ {"format": "first-last", "confidence": "medium"},
649
+ {"format": "last.f", "confidence": "medium"},
650
+ {"format": "last_first", "confidence": "medium"},
651
+ {"format": "f-last", "confidence": "medium"},
652
+ {"format": "first.l", "confidence": "medium"},
653
+ {"format": "first-l", "confidence": "medium"},
654
+ {"format": "first_l", "confidence": "medium"},
655
+ {"format": "first_last", "confidence": "medium"},
656
+ {"format": "f_last", "confidence": "medium"},
657
+ {"format": "last-first", "confidence": "medium"},
658
+ {"format": "flast", "confidence": "medium"},
659
+ {"format": "lastf", "confidence": "medium"},
660
+ {"format": "l_first", "confidence": "medium"},
661
+ {"format": "l-first", "confidence": "medium"},
662
+ {"format": "first-middle-last", "confidence": "low"},
663
+ {"format": "firstmlast", "confidence": "low"},
664
+ {"format": "last.middle.first", "confidence": "low"},
665
+ {"format": "last_middle_first", "confidence": "low"},
666
+ {"format": "first_middle_last", "confidence": "low"},
667
+ {"format": "last-middle-first", "confidence": "low"},
668
+ {"format": "first-m-last", "confidence": "low"},
669
+ {"format": "firstmiddlelast", "confidence": "low"},
670
+ {"format": "last.m.first", "confidence": "low"},
671
+ {"format": "lastmfirst", "confidence": "low"},
672
+ {"format": "lastmiddlefirst", "confidence": "low"},
673
+ {"format": "last_m_first", "confidence": "low"},
674
+ {"format": "first.m.last", "confidence": "low"},
675
+ {"format": "first_m_last", "confidence": "low"},
676
+ {"format": "last-m-first", "confidence": "low"}
677
+ ]
678
+ }
679
+
680
+ # Find domain format by company name
681
+ Zerobounce.find_domain(company_name: "Zero Bounce")
682
+ =>
683
+ {
684
+ "domain": "zerobounce.net",
685
+ "company_name": "Zero Bounce",
686
+ "format": "first.last",
687
+ "confidence": "high",
688
+ "did_you_mean": "",
689
+ "failure_reason": "",
690
+ "other_domain_formats": [...]
691
+ }
455
692
  ```
456
693
 
457
694
  ## Development
458
695
 
459
- After checking out the repo run tests
696
+ ### Local setup
697
+ ```bash
698
+ sudo apt install -y rbenv
699
+ git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build
700
+ rbenv install 3.2.1
701
+ rbenv global 3.2.1
702
+ rbenv rehash
703
+ ruby -v
704
+ gem install bundler -v "~>2.4.6"
705
+ bundle install
706
+ ```
707
+
708
+ ### Run tests
460
709
  ```bash
461
- rspec --init # if needed
462
710
  bundle exec rspec
463
711
  ```
464
712
 
465
713
  You should see an output like this
466
714
  ```bash
467
- Run options: include {:focus=>true}
468
- running live tests
715
+ running mock tests
469
716
  .....................................................
470
717
 
471
718
  Finished in 6.81 seconds (files took 0.40587 seconds to load)
@@ -474,17 +721,23 @@ Finished in 6.81 seconds (files took 0.40587 seconds to load)
474
721
 
475
722
  ### Test parameters
476
723
  The tests use the following environment parameters:
477
- TEST {unit|live} influences whether mocked unit tests are run or the live server is used (credits may be used if you choose to do this)
478
- ZEROBOUNCE_API_KEY {<zerobounce-api-key-value>} this key is used to make requests to the live server; it is also used in mock tests as a valid key sample (any value will work for mock tests)
724
+ ZEROBOUNCE_API_KEY {<zerobounce-api-key-value>} this key is used in mock tests as a valid key sample (any value will work for mock tests)
479
725
  INCORRECT_API_KEY {any non whitespace string value that is not a valid key} used for tests where the requests are meant to fail due to the API key value.
480
726
 
481
727
  To set them
482
728
  ```bash
483
729
  export ZEROBOUNCE_API_KEY=99e7ef20ceea4480a173b07b1be75371
484
730
  export INCORRECT_API_KEY=thiskeyisinvalidorotherwiseincorrect
485
- export TEST=unit
486
731
  ```
487
732
 
488
733
  A .env.sample file is provided.
489
734
 
490
- Mock tests were generated using webmock and vcr. This means that actual requests were made and recorded in the spec/cassettes with an (at the time) valid API key used for testing purposes. This key has been invalidated in the meantime, however it is provided in the .env.sample file for the mock tests to work. If you do not wish to use this key for mocks, you can replace it with any value in the .yml files under spec/cassettes or delete all of them and rerun the tests so that vcr records them with a new key.
735
+ Tests use webmock and vcr for mocking HTTP requests. This means that actual requests were made and recorded in the spec/cassettes with an (at the time) valid API key used for testing purposes. This key has been invalidated in the meantime, however it is provided in the .env.sample file for the mock tests to work. If you do not wish to use this key for mocks, you can replace it with any value in the .yml files under spec/cassettes or delete all of them and rerun the tests so that vcr records them with a new key.
736
+
737
+ ### Publish
738
+ ```bash
739
+ gem signin
740
+ gem build zerobounce.spec
741
+ gem push zerobounce-sdk-<version>.gem
742
+ gem search zerobounce-sdk --remote
743
+ ```
data/documentation.md CHANGED
@@ -400,6 +400,81 @@ Zerobounce.guessformat("zerobounce.net")
400
400
  # Zerobounce.guessformat("zerobounce.net", first_name: "John", middle_name: 'Deere', last_name: "Doe")
401
401
  ```
402
402
 
403
+ Find Email Address
404
+ ```ruby
405
+ Zerobounce.find_email("John", domain: "zerobounce.net")
406
+ =>
407
+ {
408
+ "email": "john@zerobounce.net",
409
+ "email_confidence": "medium",
410
+ "domain": "zerobounce.net",
411
+ "company_name": "ZeroBounce",
412
+ "did_you_mean": "",
413
+ "failure_reason": ""
414
+ }
415
+
416
+ # With additional name information for better accuracy
417
+ Zerobounce.find_email("John", domain: "zerobounce.net", middle_name: "Deere", last_name: "Doe")
418
+ ```
419
+
420
+ Find Domain Information
421
+ ```ruby
422
+ Zerobounce.find_domain(domain: "zerobounce.net")
423
+ =>
424
+ {
425
+ "domain": "zerobounce.net",
426
+ "company_name": "Hertza, LLC",
427
+ "format": "first.last",
428
+ "confidence": "high",
429
+ "did_you_mean": "",
430
+ "failure_reason": "",
431
+ "other_domain_formats": [
432
+ {"format": "first", "confidence": "high"},
433
+ {"format": "last.first", "confidence": "high"},
434
+ {"format": "lastfirst", "confidence": "high"},
435
+ {"format": "firstl", "confidence": "high"},
436
+ {"format": "lfirst", "confidence": "high"},
437
+ {"format": "firstlast", "confidence": "high"},
438
+ {"format": "last_middle_f", "confidence": "high"},
439
+ {"format": "last", "confidence": "high"},
440
+ {"format": "f.last", "confidence": "medium"},
441
+ {"format": "last-f", "confidence": "medium"},
442
+ {"format": "l.first", "confidence": "medium"},
443
+ {"format": "last_f", "confidence": "medium"},
444
+ {"format": "first.middle.last", "confidence": "medium"},
445
+ {"format": "first-last", "confidence": "medium"},
446
+ {"format": "last.f", "confidence": "medium"},
447
+ {"format": "last_first", "confidence": "medium"},
448
+ {"format": "f-last", "confidence": "medium"},
449
+ {"format": "first.l", "confidence": "medium"},
450
+ {"format": "first-l", "confidence": "medium"},
451
+ {"format": "first_l", "confidence": "medium"},
452
+ {"format": "first_last", "confidence": "medium"},
453
+ {"format": "f_last", "confidence": "medium"},
454
+ {"format": "last-first", "confidence": "medium"},
455
+ {"format": "flast", "confidence": "medium"},
456
+ {"format": "lastf", "confidence": "medium"},
457
+ {"format": "l_first", "confidence": "medium"},
458
+ {"format": "l-first", "confidence": "medium"},
459
+ {"format": "first-middle-last", "confidence": "low"},
460
+ {"format": "firstmlast", "confidence": "low"},
461
+ {"format": "last.middle.first", "confidence": "low"},
462
+ {"format": "last_middle_first", "confidence": "low"},
463
+ {"format": "first_middle_last", "confidence": "low"},
464
+ {"format": "last-middle-first", "confidence": "low"},
465
+ {"format": "first-m-last", "confidence": "low"},
466
+ {"format": "firstmiddlelast", "confidence": "low"},
467
+ {"format": "last.m.first", "confidence": "low"},
468
+ {"format": "lastmfirst", "confidence": "low"},
469
+ {"format": "lastmiddlefirst", "confidence": "low"},
470
+ {"format": "last_m_first", "confidence": "low"},
471
+ {"format": "first.m.last", "confidence": "low"},
472
+ {"format": "first_m_last", "confidence": "low"},
473
+ {"format": "last-m-first", "confidence": "low"}
474
+ ]
475
+ }
476
+ ```
477
+
403
478
 
404
479
  #### Development
405
480
 
data/documentation_es.md CHANGED
@@ -412,6 +412,81 @@ Zerobounce.guessformat("zerobounce.net")
412
412
  # Zerobounce.guessformat("zerobounce.net", first_name: "John", middle_name: 'Deere', last_name: "Doe")
413
413
  ```
414
414
 
415
+ Encontrar Dirección de Email
416
+ ```ruby
417
+ Zerobounce.find_email("John", domain: "zerobounce.net")
418
+ =>
419
+ {
420
+ "email": "john@zerobounce.net",
421
+ "email_confidence": "medium",
422
+ "domain": "zerobounce.net",
423
+ "company_name": "ZeroBounce",
424
+ "did_you_mean": "",
425
+ "failure_reason": ""
426
+ }
427
+
428
+ # Con información adicional de nombres para mayor precisión
429
+ Zerobounce.find_email("John", domain: "zerobounce.net", middle_name: "Deere", last_name: "Doe")
430
+ ```
431
+
432
+ Encontrar Información del Dominio
433
+ ```ruby
434
+ Zerobounce.find_domain(domain: "zerobounce.net")
435
+ =>
436
+ {
437
+ "domain": "zerobounce.net",
438
+ "company_name": "Hertza, LLC",
439
+ "format": "first.last",
440
+ "confidence": "high",
441
+ "did_you_mean": "",
442
+ "failure_reason": "",
443
+ "other_domain_formats": [
444
+ {"format": "first", "confidence": "high"},
445
+ {"format": "last.first", "confidence": "high"},
446
+ {"format": "lastfirst", "confidence": "high"},
447
+ {"format": "firstl", "confidence": "high"},
448
+ {"format": "lfirst", "confidence": "high"},
449
+ {"format": "firstlast", "confidence": "high"},
450
+ {"format": "last_middle_f", "confidence": "high"},
451
+ {"format": "last", "confidence": "high"},
452
+ {"format": "f.last", "confidence": "medium"},
453
+ {"format": "last-f", "confidence": "medium"},
454
+ {"format": "l.first", "confidence": "medium"},
455
+ {"format": "last_f", "confidence": "medium"},
456
+ {"format": "first.middle.last", "confidence": "medium"},
457
+ {"format": "first-last", "confidence": "medium"},
458
+ {"format": "last.f", "confidence": "medium"},
459
+ {"format": "last_first", "confidence": "medium"},
460
+ {"format": "f-last", "confidence": "medium"},
461
+ {"format": "first.l", "confidence": "medium"},
462
+ {"format": "first-l", "confidence": "medium"},
463
+ {"format": "first_l", "confidence": "medium"},
464
+ {"format": "first_last", "confidence": "medium"},
465
+ {"format": "f_last", "confidence": "medium"},
466
+ {"format": "last-first", "confidence": "medium"},
467
+ {"format": "flast", "confidence": "medium"},
468
+ {"format": "lastf", "confidence": "medium"},
469
+ {"format": "l_first", "confidence": "medium"},
470
+ {"format": "l-first", "confidence": "medium"},
471
+ {"format": "first-middle-last", "confidence": "low"},
472
+ {"format": "firstmlast", "confidence": "low"},
473
+ {"format": "last.middle.first", "confidence": "low"},
474
+ {"format": "last_middle_first", "confidence": "low"},
475
+ {"format": "first_middle_last", "confidence": "low"},
476
+ {"format": "last-middle-first", "confidence": "low"},
477
+ {"format": "first-m-last", "confidence": "low"},
478
+ {"format": "firstmiddlelast", "confidence": "low"},
479
+ {"format": "last.m.first", "confidence": "low"},
480
+ {"format": "lastmfirst", "confidence": "low"},
481
+ {"format": "lastmiddlefirst", "confidence": "low"},
482
+ {"format": "last_m_first", "confidence": "low"},
483
+ {"format": "first.m.last", "confidence": "low"},
484
+ {"format": "first_m_last", "confidence": "low"},
485
+ {"format": "last-m-first", "confidence": "low"}
486
+ ]
487
+ }
488
+ ```
489
+
415
490
 
416
491
  #### Desarrollo
417
492
 
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Zerobounce
4
+ # API URL constants for Zerobounce endpoints
5
+ #
6
+ # This class provides constant values for different Zerobounce API endpoints
7
+ # that can be accessed publicly by gem users.
8
+ #
9
+ class ApiUrls
10
+ # API URLs
11
+ DEFAULT_URL = 'https://api.zerobounce.net/v2/'
12
+ EU_URL = 'https://api-eu.zerobounce.net/v2/'
13
+ US_URL = 'https://api-us.zerobounce.net/v2/'
14
+
15
+ # Bulk API URLs
16
+ BULK_DEFAULT_URL = 'https://bulkapi.zerobounce.net/v2/'
17
+ end
18
+ end
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'rest-client'
4
4
  require 'dotenv'
5
+ require_relative 'api_urls'
5
6
 
6
7
  module Zerobounce
7
8
  # Configuration object for Zerobounce.
@@ -17,20 +18,23 @@ module Zerobounce
17
18
  # @attr [String] apikey
18
19
  # A Zerobounce API key.
19
20
  #
21
+ # @attr [String] api_root_url
22
+ # The Zerobounce API root URL. Defaults to ApiUrls::DEFAULT_URL.
23
+ #
24
+ # @attr [String] bulk_api_root_url
25
+ # The Zerobounce bulk API root URL.
26
+ #
20
27
  # @attr [Array<Symbol>] valid_statues
21
28
  # The statuses that are considered valid by {Response#valid?}.
22
29
  class Configuration
23
- attr_accessor :host
24
- attr_accessor :headers
25
- attr_accessor :apikey
26
- attr_accessor :valid_statuses
27
- attr_accessor :mock
30
+ attr_accessor :headers, :apikey, :api_root_url, :bulk_api_root_url, :valid_statuses, :mock
28
31
 
29
- def initialize(mock=false)
30
- if File.file?(".env") then Dotenv.load(".env") else Dotenv.load end
31
- self.host = 'https://api.zerobounce.net'
32
+ def initialize(mock = false)
33
+ File.file?('.env') ? Dotenv.load('.env') : Dotenv.load
32
34
  self.apikey = ENV['ZEROBOUNCE_API_KEY']
33
- self.valid_statuses = %i[valid catch_all]
35
+ self.api_root_url = ENV['ZEROBOUNCE_API_URL'] || ApiUrls::DEFAULT_URL
36
+ self.bulk_api_root_url = ENV['ZEROBOUNCE_BULK_API_URL'] || ApiUrls::BULK_DEFAULT_URL
37
+ self.valid_statuses = %i[valid catch_all accept_all]
34
38
  self.headers = { user_agent: "ZerobounceRubyGem/#{Zerobounce::VERSION}" }
35
39
  self.mock = mock
36
40
  end
@@ -8,7 +8,7 @@ module Zerobounce
8
8
  class MockRequest < BaseRequest
9
9
 
10
10
  def self.get(path, params, content_type='application/json')
11
- response = self._get(Zerobounce::API_ROOT_URL, path, params, content_type)
11
+ response = self._get(Zerobounce.configuration.api_root_url, path, params, content_type)
12
12
  if response.headers[:content_type] == 'application/json'
13
13
  response_body = response.body
14
14
  response_body_json = JSON.parse(response_body)
@@ -25,7 +25,7 @@ module Zerobounce
25
25
  end
26
26
 
27
27
  def self.bulk_get(path, params, content_type='application/json')
28
- response = self._get(Zerobounce::BULK_API_ROOT_URL, path, params, content_type)
28
+ response = self._get(Zerobounce.configuration.bulk_api_root_url, path, params, content_type)
29
29
  if response.headers[:content_type] == 'application/json'
30
30
  response_body = response.body
31
31
  response_body_json = JSON.parse(response_body)
@@ -42,7 +42,7 @@ module Zerobounce
42
42
  end
43
43
 
44
44
  def self.bulk_post(path, params, content_type='application/json', filepath=nil)
45
- response = self._post(Zerobounce::BULK_API_ROOT_URL, path, params, \
45
+ response = self._post(Zerobounce.configuration.bulk_api_root_url, path, params, \
46
46
  content_type, filepath)
47
47
  if response.headers[:content_type] == 'application/json'
48
48
  response_body = response.body
@@ -9,7 +9,7 @@ module Zerobounce
9
9
  class Request < BaseRequest
10
10
 
11
11
  def self.get(path, params, content_type='application/json')
12
- response = self._get(Zerobounce::API_ROOT_URL, path, params, content_type)
12
+ response = self._get(Zerobounce.configuration.api_root_url, path, params, content_type)
13
13
  if response.headers[:content_type] == 'application/json'
14
14
  response_body = response.body
15
15
  response_body_json = JSON.parse(response_body)
@@ -29,7 +29,7 @@ module Zerobounce
29
29
  end
30
30
 
31
31
  def self.bulk_get(path, params, content_type='application/json')
32
- response = self._get(Zerobounce::BULK_API_ROOT_URL, path, params, content_type)
32
+ response = self._get(Zerobounce.configuration.bulk_api_root_url, path, params, content_type)
33
33
  if response.headers[:content_type] == 'application/json'
34
34
  response_body = response.body
35
35
  response_body_json = JSON.parse(response_body)
@@ -48,7 +48,7 @@ module Zerobounce
48
48
  end
49
49
 
50
50
  def self.bulk_post(path, params, content_type='application/json', filepath=nil)
51
- response = self._post(Zerobounce::BULK_API_ROOT_URL, path, params, \
51
+ response = self._post(Zerobounce.configuration.bulk_api_root_url, path, params, \
52
52
  content_type, filepath)
53
53
  if response.headers[:content_type] == 'application/json'
54
54
  response_body = response.body
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Zerobounce
4
4
  # The version of the gem.
5
- VERSION = '1.1.2'
5
+ VERSION = '1.2.0'
6
6
  end
data/lib/zerobounce.rb CHANGED
@@ -8,13 +8,11 @@ require 'zerobounce/version'
8
8
  require 'zerobounce/request'
9
9
  require 'zerobounce/mock_request'
10
10
  require 'zerobounce/configuration'
11
+ require 'zerobounce/api_urls'
11
12
 
12
13
  # Validate an email address with Zerobounce.net
13
14
  module Zerobounce
14
15
 
15
- API_ROOT_URL = 'https://api.zerobounce.net/v2'
16
- BULK_API_ROOT_URL = 'https://bulkapi.zerobounce.net/v2'
17
-
18
16
  class << self
19
17
  attr_writer :configuration
20
18
 
@@ -427,19 +425,118 @@ module Zerobounce
427
425
  # ]
428
426
  # }
429
427
  def guessformat(domain, first_name: '', middle_name: '', last_name: '')
430
- params = {
431
- domain: domain
432
- }
433
- unless first_name.empty?
434
- params['first_name'] = first_name
435
- end
436
- unless middle_name.empty?
437
- params['middle_name'] = middle_name
428
+ params = {domain: domain}
429
+ params[:first_name] = first_name unless first_name.nil? || first_name.empty?
430
+ params[:middle_name] = middle_name unless middle_name.nil? || middle_name.empty?
431
+ params[:last_name] = last_name unless last_name.nil? || last_name.empty?
432
+ @@request.get('guessformat', params)
433
+ end
434
+
435
+
436
+ # Find email address format
437
+ #
438
+ # @option [String] domain Domain to search within (e.g. example.com). Required if company_name is not provided.
439
+ # @option [String] company_name Company name to search within (e.g. Example). Required if domain is not provided.
440
+ # @option [String] first_name First name of target.
441
+ # @option [String] middle_name Middle name of target.
442
+ # @option [String] last_name Last name of target.
443
+ #
444
+ # @return [Hash]
445
+ # {
446
+ # "email": "john@zerobounce.net",
447
+ # "email_confidence": "medium",
448
+ # "domain": "zerobounce.net",
449
+ # "company_name": "ZeroBounce",
450
+ # "did_you_mean": "",
451
+ # "failure_reason": ""
452
+ # }
453
+ def find_email(first_name, domain: '', company_name: '', middle_name: '', last_name: '')
454
+ # Validate that exactly one of domain or company_name is provided
455
+ if (domain.nil? || domain.empty?) && (company_name.nil? || company_name.empty?)
456
+ raise ArgumentError, "Either domain or company_name must be provided"
457
+ elsif !(domain.nil? || domain.empty?) && !(company_name.nil? || company_name.empty?)
458
+ raise ArgumentError, "Only one of domain or company_name can be provided"
438
459
  end
439
- unless last_name.empty?
440
- params['last_name'] = last_name
460
+
461
+ params = { first_name: first_name }
462
+ params[:domain] = domain unless domain.nil? || domain.empty?
463
+ params[:company_name] = company_name unless company_name.nil? || company_name.empty?
464
+ params[:middle_name] = middle_name unless middle_name.nil? || middle_name.empty?
465
+ params[:last_name] = last_name unless last_name.nil? || last_name.empty?
466
+
467
+ @@request.get('guessformat', params)
468
+ end
469
+
470
+ # Find domain format
471
+ #
472
+ # @option [String] domain Domain to search within (e.g. example.com). Required if company_name is not provided.
473
+ # @option [String] company_name Company name to search within (e.g. Example). Required if domain is not provided.
474
+ #
475
+ # @return [Hash]
476
+ # {
477
+ # "domain": "zerobounce.net",
478
+ # "company_name": "Hertza, LLC",
479
+ # "format": "first.last",
480
+ # "confidence": "high",
481
+ # "did_you_mean": "",
482
+ # "failure_reason": "",
483
+ # "other_domain_formats": [
484
+ # {"format": "first", "confidence": "high"},
485
+ # {"format": "last.first", "confidence": "high"},
486
+ # {"format": "lastfirst", "confidence": "high"},
487
+ # {"format": "firstl", "confidence": "high"},
488
+ # {"format": "lfirst", "confidence": "high"},
489
+ # {"format": "firstlast", "confidence": "high"},
490
+ # {"format": "last_middle_f", "confidence": "high"},
491
+ # {"format": "last", "confidence": "high"},
492
+ # {"format": "f.last", "confidence": "medium"},
493
+ # {"format": "last-f", "confidence": "medium"},
494
+ # {"format": "l.first", "confidence": "medium"},
495
+ # {"format": "last_f", "confidence": "medium"},
496
+ # {"format": "first.middle.last", "confidence": "medium"},
497
+ # {"format": "first-last", "confidence": "medium"},
498
+ # {"format": "last.f", "confidence": "medium"},
499
+ # {"format": "last_first", "confidence": "medium"},
500
+ # {"format": "f-last", "confidence": "medium"},
501
+ # {"format": "first.l", "confidence": "medium"},
502
+ # {"format": "first-l", "confidence": "medium"},
503
+ # {"format": "first_l", "confidence": "medium"},
504
+ # {"format": "first_last", "confidence": "medium"},
505
+ # {"format": "f_last", "confidence": "medium"},
506
+ # {"format": "last-first", "confidence": "medium"},
507
+ # {"format": "flast", "confidence": "medium"},
508
+ # {"format": "lastf", "confidence": "medium"},
509
+ # {"format": "l_first", "confidence": "medium"},
510
+ # {"format": "l-first", "confidence": "medium"},
511
+ # {"format": "first-middle-last", "confidence": "low"},
512
+ # {"format": "firstmlast", "confidence": "low"},
513
+ # {"format": "last.middle.first", "confidence": "low"},
514
+ # {"format": "last_middle_first", "confidence": "low"},
515
+ # {"format": "first_middle_last", "confidence": "low"},
516
+ # {"format": "last-middle-first", "confidence": "low"},
517
+ # {"format": "first-m-last", "confidence": "low"},
518
+ # {"format": "firstmiddlelast", "confidence": "low"},
519
+ # {"format": "last.m.first", "confidence": "low"},
520
+ # {"format": "lastmfirst", "confidence": "low"},
521
+ # {"format": "lastmiddlefirst", "confidence": "low"},
522
+ # {"format": "last_m_first", "confidence": "low"},
523
+ # {"format": "first.m.last", "confidence": "low"},
524
+ # {"format": "first_m_last", "confidence": "low"},
525
+ # {"format": "last-m-first", "confidence": "low"}
526
+ # ]
527
+ # }
528
+ def find_domain(domain: '', company_name: '')
529
+ # Validate that exactly one of domain or company_name is provided
530
+ if (domain.nil? || domain.empty?) && (company_name.nil? || company_name.empty?)
531
+ raise ArgumentError, "Either domain or company_name must be provided"
532
+ elsif !(domain.nil? || domain.empty?) && !(company_name.nil? || company_name.empty?)
533
+ raise ArgumentError, "Only one of domain or company_name can be provided"
441
534
  end
442
535
 
536
+ params = {}
537
+ params[:domain] = domain unless domain.nil? || domain.empty?
538
+ params[:company_name] = company_name unless company_name.nil? || company_name.empty?
539
+
443
540
  @@request.get('guessformat', params)
444
541
  end
445
542
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: zerobounce-sdk
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.2
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Zero Bounce
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-08-28 00:00:00.000000000 Z
11
+ date: 2025-10-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rest-client
@@ -258,6 +258,7 @@ files:
258
258
  - files/zerobounce-ai-scoring.csv
259
259
  - files/zerobounce-batch-validation.csv
260
260
  - lib/zerobounce.rb
261
+ - lib/zerobounce/api_urls.rb
261
262
  - lib/zerobounce/base_request.rb
262
263
  - lib/zerobounce/configuration.rb
263
264
  - lib/zerobounce/error.rb
@@ -270,7 +271,7 @@ licenses:
270
271
  - MIT
271
272
  metadata:
272
273
  yard.run: yri
273
- post_install_message:
274
+ post_install_message:
274
275
  rdoc_options: []
275
276
  require_paths:
276
277
  - lib
@@ -286,7 +287,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
286
287
  version: '0'
287
288
  requirements: []
288
289
  rubygems_version: 3.4.6
289
- signing_key:
290
+ signing_key:
290
291
  specification_version: 4
291
292
  summary: A Ruby client for Zerobounce.net.
292
293
  test_files: []