Production-ready Ruby and Rails code examples for BounceZero email verification - from a simple Net::HTTP request to a full Rails custom validator, Devise registration hook, Sidekiq background worker, and batch CSV enrichment pattern.
require "net/http"
require "uri"
require "json"
API_KEY = ENV["BOUNCEZERO_API_KEY"]
BASE_URL = "https://api.bouncezero.io/v1"
def verify_email(email)
uri = URI("#{BASE_URL}/verify")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer #{API_KEY}"
request["Content-Type"] = "application/json"
request.body = { email: email }.to_json
response = http.request(request)
JSON.parse(response.body, symbolize_names: true)
end
result = verify_email("[email protected]")
puts result
# => {
# email: "[email protected]",
# result: "valid", # "valid" | "invalid" | "unknown" | "catch-all"
# score: 0.97,
# is_disposable: false,
# is_role_address: false,
# mx_valid: true,
# provider: "Google Workspace"
# }
require "faraday"
require "json"
API_KEY = ENV["BOUNCEZERO_API_KEY"]
def bouncezero_client
Faraday.new("https://api.bouncezero.io") do |f|
f.request :json
f.response :json, symbolize_names: true
f.headers["Authorization"] = "Bearer #{API_KEY}"
end
end
def verify_email(email)
response = bouncezero_client.post("/v1/verify", { email: email })
response.body
end
result = verify_email("[email protected]")
puts result[:result] # => "valid"
puts result[:score] # => 0.96
Add real-time verification to any Rails model attribute at validation time.
require "net/http"
require "json"
class BounceZeroEmailValidator < ActiveModel::EachValidator
API_KEY = ENV["BOUNCEZERO_API_KEY"]
ENDPOINT = URI("https://api.bouncezero.io/v1/verify")
def validate_each(record, attribute, value)
return if value.blank?
result = call_api(value)
return unless result
if result[:result] == "invalid"
record.errors.add(attribute, :invalid, message: "doesn't appear to be a valid email address")
elsif result[:is_disposable]
record.errors.add(attribute, :disposable, message: "Please use a work or personal email address")
end
rescue StandardError
# Fail open on API errors - do not block signup
end
private
def call_api(email)
http = Net::HTTP.new(ENDPOINT.host, ENDPOINT.port)
http.use_ssl = true
req = Net::HTTP::Post.new(ENDPOINT)
req["Authorization"] = "Bearer #{API_KEY}"
req["Content-Type"] = "application/json"
req.body = { email: email }.to_json
res = http.request(req)
JSON.parse(res.body, symbolize_names: true)
end
end
# In your User model:
# validates :email, presence: true, bouncezero_email: true
Run verification asynchronously to avoid blocking the signup response. Flag the account for review if the email fails post-creation.
class EmailVerificationWorker
include Sidekiq::Worker
sidekiq_options retry: 2, queue: :verification
def perform(user_id)
user = User.find_by(id: user_id)
return unless user
result = BounceZeroService.verify(user.email)
return unless result
case result[:result]
when "invalid"
user.update!(email_verified_at: nil, email_status: "invalid")
# Optional: flag for manual review or send re-registration prompt
when "valid", "catch-all"
user.update!(email_verified_at: Time.current, email_status: result[:result])
end
user.update!(
email_disposable: result[:is_disposable],
email_score: result[:score]
)
end
end
# Trigger from UsersController#create or Devise registrations_controller:
# EmailVerificationWorker.perform_async(@user.id)
| Field | Type | Values | Use for |
|---|---|---|---|
| result | String | valid / invalid / unknown / catch-all | Primary routing decision |
| score | Float | 0.0 - 1.0 | Threshold-based filtering for catch-all decisions |
| is_disposable | Boolean | true / false | Block throwaway addresses at signup |
| is_role_address | Boolean | true / false | Flag info@ / admin@ / support@ |
| mx_valid | Boolean | true / false | Domain has active MX - basic health check |
| provider | String | “Gmail” / “Outlook” / etc. | Route to provider-specific logic or personalise |
New to verification? Start with the complete email verification guide.
Use Net::HTTP (built-in) or Faraday to POST to https://api.bouncezero.io/v1/verify with your API key in the Authorization header and {email: address} as a JSON body. Parse the response and check the result field: ‘valid’, ‘invalid’, ‘unknown’, or ‘catch-all’.
Create a custom ActiveModel::EachValidator that calls BounceZero during validation. Add validates :email, bouncezero_email: true to your User model. The validator adds errors to the email attribute for invalid addresses and disposable domains. Fail open on API errors to avoid blocking legitimate signups.
Run verification post-signup in a Sidekiq worker triggered from a Devise after_sign_up hook. The worker calls BounceZero, updates the user’s email_status, and flags invalid accounts for review. Async avoids blocking the signup UX on an external API response.
100 free credits on signup. No credit card. Instant access to the verification API. $3/1K thereafter - credits never expire.
Endpoints, code samples, and language guides
net/http, concurrent worker pool, Gin middleware, fail-open signup validation - code examples
Integration guide: requests, async httpx, batch CSV, Flask/Django patterns
cURL, Guzzle, Laravel rule, WordPress registration hook - code examples
IHttpClientFactory, ASP.NET Core minimal API, IHostedService bulk queue - code examples
HttpClient, ExecutorService bulk pool, Spring Boot bean wiring, fail-open signup validation - code examples
net/http single check, goroutine worker pool, context deadline, Gin middleware - code examples
Continue through related topics