zerobounce-sdk 1.1.1 → 2.1.8

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.
data/LICENSE.txt CHANGED
@@ -1,6 +1,6 @@
1
- The MIT License (MIT)
1
+ MIT License
2
2
 
3
- Copyright (c) 2018 Aaron Frase
3
+ Copyright (c) 2026 ZeroBounce
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -9,13 +9,13 @@ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
9
  copies of the Software, and to permit persons to whom the Software is
10
10
  furnished to do so, subject to the following conditions:
11
11
 
12
- The above copyright notice and this permission notice shall be included in
13
- all copies or substantial portions of the Software.
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
14
 
15
15
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
16
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
17
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
18
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
19
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
- THE SOFTWARE.
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
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
37
88
  ```
38
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
128
+ ```
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
@@ -80,10 +189,13 @@ Zerobounce.api_usage(Date.today, Date.today)
80
189
  "sub_status_mailbox_quota_exceeded"=>0,
81
190
  "sub_status_forcible_disconnect"=>0,
82
191
  "sub_status_failed_smtp_connection"=>0,
192
+ "sub_status_accept_all"=>0,
83
193
  "sub_status_mx_forward"=>0,
84
194
  "sub_status_alternate"=>0,
85
- "sub_status_blocked"=>0,
86
195
  "sub_status_allowed"=>0,
196
+ "sub_status_blocked"=>0,
197
+ "sub_status_gold"=>0,
198
+ "sub_status_role_based_accept_all"=>0,
87
199
  "start_date"=>"4/28/2023",
88
200
  "end_date"=>"4/28/2023"}
89
201
  ```
@@ -269,10 +381,13 @@ Send file
269
381
  last_name_column: 3,
270
382
  gender_column: 4,
271
383
  has_header_row: true,
272
- return_url: nil # results callback url
384
+ return_url: nil, # results callback url
385
+ allow_phase_2: true # optional; validation bulk sendfile only (omit or nil to skip)
273
386
  # Zerobounce.validate_file_send(validate_file_path, email_address_column: 1, gender_column: 4)
274
387
  ```
275
388
 
389
+ Bulk validation uses `https://bulkapi.zerobounce.net/v2`. See [v2 send file](https://www.zerobounce.net/docs/email-validation-api-quickstart/v2-send-file), [v2 file status](https://www.zerobounce.net/docs/email-validation-api-quickstart/v2-file-status), and [v2 get file](https://www.zerobounce.net/docs/email-validation-api-quickstart/v2-get-file).
390
+
276
391
  Check file
277
392
  ```ruby
278
393
  file_id = "75d854a6-565c-49f9-b4c8-b3344480ec4c"
@@ -285,6 +400,7 @@ Zerobounce.validate_file_check(file_id)
285
400
  "upload_date"=>"2023-04-28T15:25:41Z",
286
401
  "file_status"=>"Greylisted",
287
402
  "complete_percentage"=>"0%",
403
+ "file_phase_2_status"=>"N/A", # when present (validation bulk v2)
288
404
  "error_reason"=>nil,
289
405
  "return_url"=>nil}
290
406
  ```
@@ -297,6 +413,18 @@ Zerobounce.validate_file_get(file_id)
297
413
  => "\"email\",\"first\",\"last\",\"gender\",\"ip\",\"ZB Status\",\"ZB Sub Status\",\"ZB Account\",\"ZB Domain\",\"ZB First Name\",\"ZB Last Name\",\"ZB Gender\",\"ZB Free Email\",\"ZB MX Found\",\"ZB MX Record\",\"ZB SMTP Provider\",\"ZB Did You Mean\"\n\"disposable@example.com\",\"First\",\"Last\",\"male\",\"127.0.0.1\",\"do_not_mail\",\"disposable\",\"\",\"\",\"zero\",\"bounce\",\"male\",\"False\",\"true\",\"mx.example.com\",\"example\",\"\"\n\"invalid@example.com\",\"First\",\"Last\",\"male\",\"127.0.0.1\",\"invalid\",\"mailbox_not_found\",\"\",\"\",\"zero\",\"bounce\",\"male\",\"False\",\"true\",\"mx.example.com\",\"example\",\"\"\n\"valid@example.com\",\"First\",\"Last\",\"male\",\"127.0.0.1\",\"valid\",\"\",\"\",\"\",\"zero\",\"bounce\",\"male\",\"False\",\"true\",\"mx.example.com\",\"example\",\"\"\n\"toxic@example.com\",\"First\",\"Last\",\"male\",\"127.0.0.1\",\"do_not_mail\",\"toxic\",\"\",\"\",\"zero\",\"bounce\",\"male\",\"False\",\"true\",\"mx.example.com\",\"example\",\"\"\n\"donotmail@example.com\",\"First\",\"Last\",\"male\",\"127.0.0.1\",\"do_not_mail\",\"role_based\",\"\",\"\",\"zero\",\"bounce\",\"male\",\"False\",\"true\",\"mx.example.com\",\"example\",\"\"\n\"spamtrap@example.com\",\"First\",\"Last\",\"male\",\"127.0.0.1\",\"spamtrap\",\"\",\"\",\"\",\"zero\",\"bounce\",\"male\",\"False\",\"true\",\"mx.example.com\",\"example\",\"\"\n\"abuse@example.com\",\"First\",\"Last\",\"male\",\"127.0.0.1\",\"abuse\",\"\",\"\",\"\",\"zero\",\"bounce\",\"male\",\"False\",\"true\",\"mx.example.com\",\"example\",\"\"\n\"unknown@example.com\",\"First\",\"Last\",\"male\",\"127.0.0.1\",\"unknown\",\"mail_server_temporary_error\",\"\",\"\",\"zero\",\"bounce\",\"male\",\"False\",\"true\",\"mx.example.com\",\"example\",\"\"\n\"catch_all@example.com\",\"First\",\"Last\",\"male\",\"127.0.0.1\",\"catch-all\",\"\",\"\",\"\",\"zero\",\"bounce\",\"male\",\"False\",\"true\",\"mx.example.com\",\"example\",\"\"\n\"antispam_system@example.com\",\"First\",\"Last\",\"male\",\"127.0.0.1\",\"unknown\",\"antispam_system\",\"\",\"\",\"zero\",\"bounce\",\"male\",\"False\",\"true\",\"mx.example.com\",\"example\",\"\"\n\"does_not_accept_mail@example.com\",\"First\",\"Last\",\"male\",\"127.0.0.1\",\"invalid\",\"does_not_accept_mail\",\"\",\"\",\"zero\",\"bounce\",\"male\",\"False\",\"true\",\"mx.example.com\",\"example\",\"\"\n\"exception_occurred@example.com\",\"First\",\"Last\",\"male\",\"127.0.0.1\",\"unknown\",\"exception_occurred\",\"\",\"\",\"zero\",\"bounce\",\"male\",\"False\",\"true\",\"mx.example.com\",\"example\",\"\"\n\"failed_smtp_connection@example.com\",\"First\",\"Last\",\"male\",\"127.0.0.1\",\"unknown\",\"failed_smtp_connection\",\"\",\"\",\"zero\",\"bounce\",\"male\",\"False\",\"true\",\"mx.example.com\",\"example\",\"\"\n\"failed_syntax_check@example.com\",\"First\",\"Last\",\"male\",\"127.0.0.1\",\"invalid\",\"failed_syntax_check\",\"\",\"\",\"zero\",\"bounce\",\"male\",\"False\",\"true\",\"mx.example.com\",\"example\",\"\"\n\"forcible_disconnect@example.com\",\"First\",\"Last\",\"male\",\"127.0.0.1\",\"unknown\",\"forcible_disconnect\",\"\",\"\",\"zero\",\"bounce\",\"male\",\"False\",\"true\",\"mx.example.com\",\"example\",\"\"\n\"global_suppression@example.com\",\"First\",\"Last\",\"male\",\"127.0.0.1\",\"do_not_mail\",\"global_suppression\",\"\",\"\",\"zero\",\"bounce\",\"male\",\"False\",\"true\",\"mx.example.com\",\"example\",\"\"\n\"greylisted@example.com\",\"First\",\"Last\",\"male\",\"127.0.0.1\",\"unknown\",\"greylisted\",\"\",\"\",\"zero\",\"bounce\",\"male\",\"False\",\"true\",\"mx.example.com\",\"example\",\"\"\n\"leading_period_removed@example.com\",\"First\",\"Last\",\"male\",\"127.0.0.1\",\"valid\",\"leading_period_removed\",\"\",\"\",\"zero\",\"bounce\",\"male\",\"False\",\"true\",\"mx.example.com\",\"example\",\"\"\n\"mail_server_did_not_respond@example.com\",\"First\",\"Last\",\"male\",\"127.0.0.1\",\"unknown\",\"mail_server_did_not_respond\",\"\",\"\",\"zero\",\"bounce\",\"male\",\"False\",\"true\",\"mx.example.com\",\"example\",\"\"\n\"mail_server_temporary_error@example.com\",\"First\",\"Last\",\"male\",\"127.0.0.1\",\"unknown\",\"mail_server_temporary_error\",\"\",\"\",\"zero\",\"bounce\",\"male\",\"False\",\"true\",\"mx.example.com\",\"example\",\"\"\n\"mailbox_quota_exceeded@example.com\",\"First\",\"Last\",\"male\",\"127.0.0.1\",\"invalid\",\"mailbox_quota_exceeded\",\"\",\"\",\"zero\",\"bounce\",\"male\",\"False\",\"true\",\"mx.example.com\",\"example\",\"\"\n\"mailbox_not_found@example.com\",\"First\",\"Last\",\"male\",\"127.0.0.1\",\"invalid\",\"mailbox_not_found\",\"\",\"\",\"zero\",\"bounce\",\"male\",\"False\",\"true\",\"mx.example.com\",\"example\",\"\"\n\"no_dns_entries@example.com\",\"First\",\"Last\",\"male\",\"127.0.0.1\",\"invalid\",\"no_dns_entries\",\"\",\"\",\"zero\",\"bounce\",\"male\",\"False\",\"true\",\"mx.example.com\",\"example\",\"\"\n\"possible_trap@example.com\",\"First\",\"Last\",\"male\",\"127.0.0.1\",\"do_not_mail\",\"possible_trap\",\"\",\"\",\"zero\",\"bounce\",\"male\",\"False\",\"true\",\"mx.example.com\",\"example\",\"\"\n\"possible_typo@example.com\",\"First\",\"Last\",\"male\",\"127.0.0.1\",\"invalid\",\"possible_typo\",\"\",\"\",\"zero\",\"bounce\",\"male\",\"False\",\"true\",\"mx.example.com\",\"example\",\"\"\n\"role_based@example.com\",\"First\",\"Last\",\"male\",\"127.0.0.1\",\"do_not_mail\",\"role_based\",\"\",\"\",\"zero\",\"bounce\",\"male\",\"False\",\"true\",\"mx.example.com\",\"example\",\"\"\n\"timeout_exceeded@example.com\",\"First\",\"Last\",\"male\",\"127.0.0.1\",\"unknown\",\"timeout_exceeded\",\"\",\"\",\"zero\",\"bounce\",\"male\",\"False\",\"true\",\"mx.example.com\",\"example\",\"\"\n\"unroutable_ip_address@example.com\",\"First\",\"Last\",\"male\",\"127.0.0.1\",\"invalid\",\"unroutable_ip_address\",\"\",\"\",\"zero\",\"bounce\",\"male\",\"False\",\"true\",\"mx.example.com\",\"example\",\"\"\n\"free_email@example.com\",\"First\",\"Last\",\"male\",\"127.0.0.1\",\"valid\",\"\",\"\",\"\",\"zero\",\"bounce\",\"male\",\"True\",\"true\",\"mx.example.com\",\"example\",\"\"\n\"role_based_catch_all@example.com\",\"First\",\"Last\",\"male\",\"127.0.0.1\",\"do_not_mail\",\"role_based_catch_all\",\"\",\"\",\"zero\",\"bounce\",\"male\",\"False\",\"true\",\"mx.example.com\",\"example\",\"\"\n"
298
414
  ```
299
415
 
416
+ Optional [v2 get file](https://www.zerobounce.net/docs/email-validation-api-quickstart/v2-get-file) query parameters use `Zerobounce::GetFileOptions` and `Zerobounce::DownloadType` (`PHASE_1`, `PHASE_2`, `COMBINED`). Set `activity_data` for validation `validate_file_get` only; it is not sent for `scoring_file_get`.
417
+
418
+ ```ruby
419
+ opts = Zerobounce::GetFileOptions.new(
420
+ download_type: Zerobounce::DownloadType::COMBINED,
421
+ activity_data: true
422
+ )
423
+ csv = Zerobounce.validate_file_get(file_id, opts)
424
+ ```
425
+
426
+ Non-success HTTP responses or JSON error bodies (including some HTTP 200 responses with `"success": false`) raise `RuntimeError` with the API message. To inspect a raw body string, use `Zerobounce.get_file_json_indicates_error?(body)`.
427
+
300
428
  Delete file
301
429
  ```ruby
302
430
  file_id = "75d854a6-565c-49f9-b4c8-b3344480ec4c"
@@ -350,13 +478,15 @@ file_id = "89fb7262-b845-4fa1-aa25-e486347ec64e"
350
478
  => "89fb7262-b845-4fa1-aa25-e486347ec64e"
351
479
  Zerobounce.scoring_file_get(file_id)
352
480
  => "\"email\",\"ZeroBounceQualityScore\"\r\n\"disposable@example.com\",\"0\"\r\n\"invalid@example.com\",\"10\"\r\n\"valid@example.com\",\"10\"\r\n\"toxic@example.com\",\"2\"\r\n\"donotmail@example.com\",\"0\"\r\n\"spamtrap@example.com\",\"0\"\r\n\"abuse@example.com\",\"10\"\r\n\"unknown@example.com\",\"10\"\r\n\"catch_all@example.com\",\"10\"\r\n\"antispam_system@example.com\",\"0\"\r\n\"does_not_accept_mail@example.com\",\"0\"\r\n\"exception_occurred@example.com\",\"0\"\r\n\"failed_smtp_connection@example.com\",\"0\"\r\n\"failed_syntax_check@example.com\",\"0\"\r\n\"forcible_disconnect@example.com\",\"0\"\r\n\"global_suppression@example.com\",\"0\"\r\n\"greylisted@example.com\",\"0\"\r\n\"leading_period_removed@example.com\",\"0\"\r\n\"mail_server_did_not_respond@example.com\",\"0\"\r\n\"mail_server_temporary_error@example.com\",\"0\"\r\n\"mailbox_quota_exceeded@example.com\",\"0\"\r\n\"mailbox_not_found@example.com\",\"0\"\r\n\"no_dns_entries@example.com\",\"0\"\r\n\"possible_trap@example.com\",\"0\"\r\n\"possible_typo@example.com\",\"0\"\r\n\"role_based@example.com\",\"0\"\r\n\"timeout_exceeded@example.com\",\"0\"\r\n\"unroutable_ip_address@example.com\",\"0\"\r\n\"free_email@example.com\",\"0\"\r\n\"role_based_catch_all@example.com\",\"0\""
481
+ # Optional second argument: GetFileOptions with download_type only (activity_data is not sent for scoring getfile)
482
+ # Zerobounce.scoring_file_get(file_id, Zerobounce::GetFileOptions.new(download_type: Zerobounce::DownloadType::PHASE_2))
353
483
  ```
354
484
 
355
485
  Delete file
356
486
  ```ruby
357
487
  file_id = "89fb7262-b845-4fa1-aa25-e486347ec64e"
358
488
  => "89fb7262-b845-4fa1-aa25-e486347ec64e"
359
- Zerobounce.validate_file_delete(file_id)
489
+ Zerobounce.scoring_file_delete(file_id)
360
490
  => {"success"=>false, "message"=>"File cannot be found."}
361
491
  ```
362
492
 
@@ -412,9 +542,10 @@ When `has_header_row: false` is provided to `scoring_file_send()` method, column
412
542
 
413
543
  ### Email Finder
414
544
 
415
- Guess Format
545
+ Guess Format by Domain
416
546
  ```ruby
417
- Zerobounce.guessformat("zerobounce.net")
547
+ # New keyword argument syntax (recommended)
548
+ Zerobounce.guessformat(domain: "zerobounce.net")
418
549
  =>
419
550
  {"email"=>"",
420
551
  "domain"=>"zerobounce.net",
@@ -451,21 +582,174 @@ Zerobounce.guessformat("zerobounce.net")
451
582
  {"format"=>"lastf", "confidence"=>"medium"},
452
583
  {"format"=>"l-first", "confidence"=>"low"},
453
584
  {"format"=>"l_first", "confidence"=>"low"}]}
454
- # Zerobounce.guessformat("zerobounce.net", first_name: "John", middle_name: 'Deere', last_name: "Doe")
585
+
586
+ # With names for better accuracy (new syntax)
587
+ Zerobounce.guessformat(domain: "zerobounce.net", first_name: "John", middle_name: 'Deere', last_name: "Doe")
588
+
589
+ # Backwards compatible syntax (still supported)
590
+ Zerobounce.guessformat("zerobounce.net")
591
+ Zerobounce.guessformat("zerobounce.net", first_name: "John", middle_name: 'Deere', last_name: "Doe")
592
+ ```
593
+
594
+ Guess Format by Company Name
595
+ ```ruby
596
+ # New keyword argument syntax (recommended)
597
+ Zerobounce.guessformat(company_name: "Zero Bounce")
598
+ =>
599
+ {"email"=>"",
600
+ "company_name"=>"Zero Bounce",
601
+ "format"=>"first.last",
602
+ "status"=>"",
603
+ "sub_status"=>"",
604
+ "confidence"=>"high",
605
+ "did_you_mean"=>"",
606
+ "failure_reason"=>"",
607
+ "other_domain_formats"=>[...]}
608
+
609
+ # With names for better accuracy (new syntax)
610
+ Zerobounce.guessformat(first_name: "John", last_name: "Doe", company_name: "Zero Bounce")
611
+ ```
612
+
613
+ Find Email Address
614
+ ```ruby
615
+ # Find email by domain
616
+ Zerobounce.find_email("John", domain: "zerobounce.net")
617
+ =>
618
+ {
619
+ "email": "john@zerobounce.net",
620
+ "email_confidence": "medium",
621
+ "domain": "zerobounce.net",
622
+ "company_name": "ZeroBounce",
623
+ "did_you_mean": "",
624
+ "failure_reason": ""
625
+ }
626
+
627
+ # Find email by company name
628
+ Zerobounce.find_email("John", company_name: "Zero Bounce")
629
+ =>
630
+ {
631
+ "email": "john@zerobounce.net",
632
+ "email_confidence": "medium",
633
+ "domain": "zerobounce.net",
634
+ "company_name": "ZeroBounce",
635
+ "did_you_mean": "",
636
+ "failure_reason": ""
637
+ }
638
+
639
+ # With additional name information for better accuracy
640
+ Zerobounce.find_email("John", domain: "zerobounce.net", middle_name: "Deere", last_name: "Doe")
641
+ ```
642
+
643
+ Find Domain Information
644
+ ```ruby
645
+ # Find domain format by domain
646
+ Zerobounce.find_domain(domain: "zerobounce.net")
647
+ =>
648
+ {
649
+ "domain": "zerobounce.net",
650
+ "company_name": "Hertza, LLC",
651
+ "format": "first.last",
652
+ "confidence": "high",
653
+ "did_you_mean": "",
654
+ "failure_reason": "",
655
+ "other_domain_formats": [
656
+ {"format": "first", "confidence": "high"},
657
+ {"format": "last.first", "confidence": "high"},
658
+ {"format": "lastfirst", "confidence": "high"},
659
+ {"format": "firstl", "confidence": "high"},
660
+ {"format": "lfirst", "confidence": "high"},
661
+ {"format": "firstlast", "confidence": "high"},
662
+ {"format": "last_middle_f", "confidence": "high"},
663
+ {"format": "last", "confidence": "high"},
664
+ {"format": "f.last", "confidence": "medium"},
665
+ {"format": "last-f", "confidence": "medium"},
666
+ {"format": "l.first", "confidence": "medium"},
667
+ {"format": "last_f", "confidence": "medium"},
668
+ {"format": "first.middle.last", "confidence": "medium"},
669
+ {"format": "first-last", "confidence": "medium"},
670
+ {"format": "last.f", "confidence": "medium"},
671
+ {"format": "last_first", "confidence": "medium"},
672
+ {"format": "f-last", "confidence": "medium"},
673
+ {"format": "first.l", "confidence": "medium"},
674
+ {"format": "first-l", "confidence": "medium"},
675
+ {"format": "first_l", "confidence": "medium"},
676
+ {"format": "first_last", "confidence": "medium"},
677
+ {"format": "f_last", "confidence": "medium"},
678
+ {"format": "last-first", "confidence": "medium"},
679
+ {"format": "flast", "confidence": "medium"},
680
+ {"format": "lastf", "confidence": "medium"},
681
+ {"format": "l_first", "confidence": "medium"},
682
+ {"format": "l-first", "confidence": "medium"},
683
+ {"format": "first-middle-last", "confidence": "low"},
684
+ {"format": "firstmlast", "confidence": "low"},
685
+ {"format": "last.middle.first", "confidence": "low"},
686
+ {"format": "last_middle_first", "confidence": "low"},
687
+ {"format": "first_middle_last", "confidence": "low"},
688
+ {"format": "last-middle-first", "confidence": "low"},
689
+ {"format": "first-m-last", "confidence": "low"},
690
+ {"format": "firstmiddlelast", "confidence": "low"},
691
+ {"format": "last.m.first", "confidence": "low"},
692
+ {"format": "lastmfirst", "confidence": "low"},
693
+ {"format": "lastmiddlefirst", "confidence": "low"},
694
+ {"format": "last_m_first", "confidence": "low"},
695
+ {"format": "first.m.last", "confidence": "low"},
696
+ {"format": "first_m_last", "confidence": "low"},
697
+ {"format": "last-m-first", "confidence": "low"}
698
+ ]
699
+ }
700
+
701
+ # Find domain format by company name
702
+ Zerobounce.find_domain(company_name: "Zero Bounce")
703
+ =>
704
+ {
705
+ "domain": "zerobounce.net",
706
+ "company_name": "Zero Bounce",
707
+ "format": "first.last",
708
+ "confidence": "high",
709
+ "did_you_mean": "",
710
+ "failure_reason": "",
711
+ "other_domain_formats": [...]
712
+ }
455
713
  ```
456
714
 
457
715
  ## Development
458
716
 
459
- After checking out the repo run tests
717
+ ### Local setup
718
+ ```bash
719
+ sudo apt install -y rbenv
720
+ git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build
721
+ rbenv install 3.2.1
722
+ rbenv global 3.2.1
723
+ rbenv rehash
724
+ ruby -v
725
+ gem install bundler -v "~>2.4.6"
726
+ bundle install
727
+ ```
728
+
729
+ ### Run tests with Docker
730
+ From the **`sdk-docs/`** folder in the SDKs monorepo:
731
+
732
+ ```bash
733
+ cd sdk-docs
734
+ docker compose build ruby
735
+ docker compose run --rm ruby
736
+ ```
737
+
738
+ Or from this directory:
739
+
740
+ ```bash
741
+ docker build -t zb-ruby-sdk .
742
+ docker run --rm zb-ruby-sdk
743
+ ```
744
+
745
+ ### Run tests (local)
460
746
  ```bash
461
- rspec --init # if needed
462
747
  bundle exec rspec
463
748
  ```
464
749
 
465
750
  You should see an output like this
466
751
  ```bash
467
- Run options: include {:focus=>true}
468
- running live tests
752
+ running tests
469
753
  .....................................................
470
754
 
471
755
  Finished in 6.81 seconds (files took 0.40587 seconds to load)
@@ -473,18 +757,23 @@ Finished in 6.81 seconds (files took 0.40587 seconds to load)
473
757
  ```
474
758
 
475
759
  ### Test parameters
476
- 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)
479
- 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.
760
+ The tests use the following environment parameter:
761
+ - **ZEROBOUNCE_API_KEY** – Your API key; used in mock tests as the valid key sample (any value will work for mock tests).
762
+
763
+ An invalid API key for error-handling tests is hardcoded in the spec; no env var is required.
480
764
 
481
- To set them
765
+ To set your key:
482
766
  ```bash
483
- export ZEROBOUNCE_API_KEY=99e7ef20ceea4480a173b07b1be75371
484
- export INCORRECT_API_KEY=thiskeyisinvalidorotherwiseincorrect
485
- export TEST=unit
767
+ export ZEROBOUNCE_API_KEY=your_api_key_here
486
768
  ```
487
769
 
488
- A .env.sample file is provided.
770
+ A .env.example file is provided.
771
+
772
+ 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.example 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.
773
+
774
+ ## Publish
775
+
776
+ 1. Bump `VERSION` in `lib/zerobounce/version.rb`, commit, tag (`vX.Y.Z`), push tag.
777
+ 2. **Actions → Publish → Run workflow** with that tag.
489
778
 
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.
779
+ Registry: [zerobounce-sdk on RubyGems](https://rubygems.org/gems/zerobounce-sdk)
data/SECURITY.md ADDED
@@ -0,0 +1,21 @@
1
+ # Security Policy
2
+
3
+ ## Reporting a Vulnerability
4
+
5
+ If you think you've found a security issue, please report it privately instead of opening a public issue.
6
+
7
+ **Email:** integrations@zerobounce.net (use a subject like `[zero-bounce-ruby] Security`).
8
+
9
+ We'll look into reports as we can. If the issue is in the Zero Bounce API or service rather than this SDK, we may forward it to the right team.
10
+
11
+ ## Supported Versions
12
+
13
+ We focus on the current release line for fixes. Using the [latest version](https://rubygems.org/gems/zerobounce-sdk) is recommended.
14
+
15
+ ## Tips for Using This SDK
16
+
17
+ * Don't commit API keys or `.env` files—use environment variables or a secrets manager.
18
+ * Keep dependencies up to date with `bundle install` and upgrade when new versions are released.
19
+ * The client uses HTTPS by default; avoid overriding to non-HTTPS in production.
20
+
21
+ Thanks for helping keep things secure.