Skip to content

About

No description, website, or topics provided.

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Rust ZeroBounce API

Security

  • Keep API keys on a trusted server. Do not embed them in mobile apps or browser JavaScript that untrusted users can inspect.
  • Custom API base URLs (when supported) must use https://. Do not pass end-user-controlled hosts into those settings.
  • Request URLs include api_key as a query parameter (ZeroBounce API contract). Do not log full request URLs or enable payload debug logging in production.

This library is a wrapper for the ZeroBounce API v2.

For more information about the API, visit https://www.zerobounce.net/docs/.

How to use

This crate uses the zero-bounce API which requires an API key. Check this guide to see how to grab yours.

Check the example snippets to see how this library can be integrated in your own project.

Configuration Options

The ZeroBounce client can be configured with different base URLs depending on your region or requirements.

Default Configuration

The simplest way to create a client is using the default API URL:

use zero_bounce::ZeroBounce;

let zb = ZeroBounce::new("your_api_key");

Enum Values

You can specify a region using the ApiBaseUrl enum:

use zero_bounce::{ZeroBounce, ApiBaseUrl};

// USA region
let zb = ZeroBounce::with_base_url("your_api_key", ApiBaseUrl::USA);

// EU region
let zb = ZeroBounce::with_base_url("your_api_key", ApiBaseUrl::EU);

// Default (explicit)
let zb = ZeroBounce::with_base_url("your_api_key", ApiBaseUrl::Default);

Custom URL String

You can also provide a custom base URL as a string:

use zero_bounce::ZeroBounce;

let zb = ZeroBounce::with_base_url("your_api_key", "https://custom-api.example.com/v2/");

Available API Base URLs:

  • ApiBaseUrl::Default - https://api.zerobounce.net/v2/ (default)
  • ApiBaseUrl::USA - https://api-us.zerobounce.net/v2/
  • ApiBaseUrl::EU - https://api-eu.zerobounce.net/v2/

See the config_options example for a complete demonstration of all configuration options.

Validate options

use zero_bounce::utility::structures::validate_options::ZBValidateOptions;
use zero_bounce::ZeroBounce;

let zb = ZeroBounce::new("<YOUR_API_KEY>");

let options = ZBValidateOptions {
    // domain_info adds domain_website_exists and domain_registrant_company_name.
    domain_info: Some(true),
    // greylist_processing re-runs a greylisted address instead of returning unknown.
    greylist_processing: Some(true),
    // callback_url is only allowed together with greylist_processing: Some(true).
    callback_url: Some("https://example.com/zerobounce-callback".to_string()),
    ..Default::default()
};

let validation = zb.validate_email_with_options("someone@example.com", "", &options)?;

// While the greylist retry is still running the API returns a message instead
// of a result; validate again in about 30 minutes to pick it up.
println!("{:?} {:?}", validation.message, validation.domain_website_exists);

Inbox Placement Tester

Lives on https://bulkapi.zerobounce.net/api/ipt and spends inbox test credits.

use zero_bounce::api::inbox_placement::{
    CreateInboxPlacementTestOptions, ListInboxPlacementTestsOptions,
};
use zero_bounce::ZeroBounce;

let zb = ZeroBounce::new("<YOUR_API_KEY>");

let providers = zb.get_inbox_placement_providers()?;
let test_types = zb.get_inbox_placement_test_types()?;

// test_type 1 (Email) needs sender_email; 2 is Unique ID and 3 is Auto Alias.
let created = zb.create_inbox_placement_test(
    "October campaign", // required, at most 64 characters
    &CreateInboxPlacementTestOptions {
        test_type: Some(1),
        sender_email: Some("news@example.com".to_string()),
        webhook_url: Some("https://example.com/ipt-webhook".to_string()),
        ..Default::default()
    },
)?;

// Send your campaign to the seeds in `created`, then read the results.
let result = zb.get_inbox_placement_test("123")?;

let tests = zb.list_inbox_placement_tests(&ListInboxPlacementTestsOptions {
    status: Some("finished".to_string()),
    page: Some(1),
    page_size: Some(25),
    ..Default::default()
})?;

zb.set_inbox_placement_webhook("https://example.com/ipt-webhook")?;
let webhook = zb.get_inbox_placement_webhook()?;
zb.delete_inbox_placement_test("123")?;

S3 and SFTP/FTP bulk

Queue a job on a file that already sits in your Amazon S3 bucket, or on your SFTP/FTP server. See the S3 and SFTP docs.

let zb = ZeroBounce::new("<YOUR_API_KEY>");

// Amazon S3. file_name is the full path, as returned by list_s3_files.
// Every job takes file_name, has_header_row, remove_duplicates and return_url.
// The live API rejects a job with no return_url, so it is required here.
zb.validate_s3_file(
    "lists/leads.csv",
    true,                                        // has_header_row
    Some(true),                                  // remove_duplicates
    "https://example.com/zerobounce-done",       // return_url
)?;
zb.score_s3_file("lists/leads.csv", true, None, "https://example.com/zerobounce-done")?;
zb.email_finder_s3_file("lists/leads.csv", true, None, "https://example.com/zerobounce-done")?;
zb.domain_search_s3_file("lists/leads.csv", true, None, "https://example.com/zerobounce-done")?;

// Export back to S3. None uses the export bucket from your ZeroBounce settings.
zb.export_s3_file("<FILE_ID>", Some("my-export-bucket"))?;
zb.export_s3_file("<FILE_ID>", None)?;

// SFTP/FTP. The server, path and protocol come from your ZeroBounce settings.
zb.validate_sftp_file("my_file.txt", true, None, "https://example.com/zerobounce-done")?;
zb.score_sftp_file("my_file.txt", true, None, "https://example.com/zerobounce-done")?;
zb.email_finder_sftp_file("my_file.txt", true, None, "https://example.com/zerobounce-done")?;
zb.domain_search_sftp_file("my_file.txt", true, None, "https://example.com/zerobounce-done")?;

// Note the field: this one takes export_path, not export_bucket.
// None uses the export path from your settings.
zb.export_sftp_file("<FILE_ID>", Some("/exports"))?;

Bulk email finder and domain search files

Run the email finder or domain search over a whole file. These four-step flows (submit, status, download, delete) live on the bulk host without the /v2 path the other bulk APIs use. See the bulk email finder and domain search docs.

use zero_bounce::{ZBBulkResponse, ZBEmailFinderFileOptions, ZeroBounce};

let zb = ZeroBounce::new("<YOUR_API_KEY>");

// Email finder. domain_column is required; so is one of first_name_column or
// full_name_column — the API cannot guess a person from a domain alone.
let submitted = zb.send_email_finder_file(
    1,                                      // domain_column
    &ZBEmailFinderFileOptions {
        first_name_column: Some(2),
        last_name_column: Some(3),
        has_header_row: Some(true),
        ..Default::default()
    },
    "leads.csv",
    std::fs::File::open("leads.csv")?,
)?;
let file_id = submitted.file_id.unwrap_or_default();

zb.email_finder_file_status(&file_id)?;
if let ZBBulkResponse::Content(bytes) = zb.email_finder_result_fetch(&file_id)? {
    std::fs::write("results.csv", bytes)?;
}
zb.email_finder_result_delete(&file_id)?;

// Domain search. has_header_row is omitted when None, so the account default applies.
let submitted = zb.send_domain_search_file(
    1,                 // domain_column
    Some(true),        // has_header_row
    "domains.csv",
    std::fs::File::open("domains.csv")?,
)?;
let file_id = submitted.file_id.unwrap_or_default();

zb.domain_search_file_status(&file_id)?;
let results = zb.domain_search_result_fetch(&file_id)?;
zb.domain_search_result_delete(&file_id)?;

email_finder_result_fetch and domain_search_result_fetch follow the same rules as bulk_validation_result_fetch: the file bytes come back as ZBBulkResponse::Content, while a JSON body — including an HTTP 200 carrying {"success": false} — is an Err with a short message.

Per-API base URLs

The list evaluator and the Inbox Placement Tester have their own base URLs, separate from the main and bulk hosts.

let mut zb = ZeroBounce::new("<YOUR_API_KEY>");
zb.url_provider.list_evaluator_url =
    "https://bulkapi.zerobounce.net/v2/listevaluator".to_string();
zb.url_provider.inbox_placement_url =
    "https://bulkapi.zerobounce.net/api/ipt".to_string();

Email Finding Methods

find_email_v2 (Recommended)

Find an email address using either a domain or company name. Uses the builder pattern for ergonomic API calls.

Requirements:

  • Exactly one of domain or company_name must be provided (XOR requirement)
  • first_name is optional. Without it the API answers with the domain's address formats, the same as domain_search_v2. Setting it to an empty string is still rejected.

Builder Methods:

  • .first_name(name: &str) - Set the first name (optional)
  • .domain(domain: &str) - Set the domain name
  • .company_name(company: &str) - Set the company name
  • .middle_name(name: &str) - Set the middle name (optional)
  • .last_name(name: &str) - Set the last name (optional)
  • .call() - Execute the API call

Example:

use zero_bounce::ZeroBounce;

let zb = ZeroBounce::new("your_api_key");

// Using domain
let result = zb.find_email_v2()
    .first_name("John")
    .domain("example.com")
    .last_name("Doe")
    .call()?;

// Using company name
let result = zb.find_email_v2()
    .first_name("John")
    .company_name("Example Inc")
    .last_name("Doe")
    .call()?;

// With middle name
let result = zb.find_email_v2()
    .first_name("John")
    .domain("example.com")
    .middle_name("Middle")
    .last_name("Doe")
    .call()?;

Returns: FindEmailResponseV2 containing:

  • email: The found email address
  • domain: Domain name
  • confidence: Email confidence level (from email_confidence field)
  • company_name: Company name
  • did_you_mean: Suggested alternative
  • failure_reason: Reason for failure if any

find_email (Deprecated)

⚠️ Deprecated since version 1.2.0 - Use find_email_v2 instead.

This method is kept for backward compatibility but will be removed in a future version. The new find_email_v2 method supports both domain and company_name parameters.

Example:

let result = zb.find_email("example.com", "John", "", "Doe")?;

Domain Search Methods

domain_search_v2 (Recommended)

Search for email formats using either a domain or company name. Uses the builder pattern for ergonomic API calls.

Requirements:

  • Exactly one of domain or company_name must be provided (XOR requirement)

Builder Methods:

  • .domain(domain: &str) - Set the domain name
  • .company_name(company: &str) - Set the company name
  • .call() - Execute the API call

Example:

use zero_bounce::ZeroBounce;

let zb = ZeroBounce::new("your_api_key");

// Using domain
let result = zb.domain_search_v2()
    .domain("example.com")
    .call()?;

// Using company name
let result = zb.domain_search_v2()
    .company_name("Example Inc")
    .call()?;

Returns: DomainSearchResponseV2 containing:

  • domain: Domain name
  • company_name: Company name
  • format: Email format found
  • confidence: Confidence level
  • other_domain_formats: Alternative formats with confidence levels
  • did_you_mean: Suggested alternative
  • failure_reason: Reason for failure if any

domain_search (Deprecated)

⚠️ Deprecated since version 1.2.0 - Use domain_search_v2 instead.

This method is kept for backward compatibility but will be removed in a future version. The new domain_search_v2 method supports both domain and company_name parameters.

Example:

let result = zb.domain_search("example.com")?;

Account & Usage Methods

get_credits

Get the number of credits remaining in your ZeroBounce account.

Example:

use zero_bounce::ZeroBounce;

let zb = ZeroBounce::new("your_api_key");
let credits = zb.get_credits()?;
println!("Credits remaining: {}", credits);

Returns: i64 - The number of credits remaining in your account

get_api_usage

Get API usage statistics for a specific date range.

Arguments:

  • start_date: NaiveDate - Start date for the usage period
  • end_date: NaiveDate - End date for the usage period

Example:

use zero_bounce::ZeroBounce;
use chrono::NaiveDate;

let zb = ZeroBounce::new("your_api_key");
let start = NaiveDate::from_ymd_opt(2024, 1, 1).unwrap();
let end = NaiveDate::from_ymd_opt(2024, 1, 31).unwrap();
let usage = zb.get_api_usage(start, end)?;
println!("Total API calls: {}", usage.total);

Returns: ApiUsage containing:

  • total: Total number of API calls in the period
  • status_valid: Number of valid email addresses
  • status_invalid: Number of invalid email addresses
  • status_catch_all: Number of catch-all email addresses
  • status_do_not_mail: Number of do-not-mail addresses
  • status_spamtrap: Number of spamtrap addresses
  • status_abuse: Number of abuse addresses
  • status_unknown: Number of unknown addresses
  • sub_status_antispam_system: Number of antispam system responses
  • sub_status_greylisted: Number of greylisted responses
  • sub_status_mail_server_temporary_error: Number of temporary mail server errors
  • sub_status_forcible_disconnect: Number of forcible disconnects
  • sub_status_mail_server_did_not_respond: Number of non-responsive mail servers
  • sub_status_timeout_exceeded: Number of timeout errors
  • sub_status_failed_smtp_connection: Number of failed SMTP connections
  • sub_status_mailbox_quota_exceeded: Number of mailbox quota exceeded errors
  • sub_status_exception_occurred: Number of exceptions
  • sub_status_possible_trap: Number of possible traps
  • sub_status_role_based: Number of role-based addresses
  • sub_status_global_suppression: Number of globally suppressed addresses
  • sub_status_mailbox_not_found: Number of mailbox not found errors
  • sub_status_no_dns_entries: Number of no DNS entries errors
  • sub_status_failed_syntax_check: Number of failed syntax checks
  • sub_status_possible_typo: Number of possible typos
  • sub_status_unroutable_ip_address: Number of unroutable IP addresses
  • sub_status_leading_period_removed: Number of leading periods removed
  • sub_status_does_not_accept_mail: Number of addresses that don't accept mail
  • sub_status_alias_address: Number of alias addresses
  • sub_status_role_based_catch_all: Number of role-based catch-all addresses
  • sub_status_accept_all: Number of accept-all addresses
  • sub_status_disposable: Number of disposable addresses
  • sub_status_toxic: Number of toxic addresses

get_api_usage_overall

Get overall API usage statistics from January 1, 2000 to the current date.

Example:

use zero_bounce::ZeroBounce;

let zb = ZeroBounce::new("your_api_key");
let overall_usage = zb.get_api_usage_overall()?;
println!("Total API calls overall: {}", overall_usage.total);

Returns: ApiUsage - Same structure as get_api_usage

get_activity_data

Get activity data for a specific email address, including when it was last seen sending emails.

Arguments:

  • email: &str - The email address to check

Example:

use zero_bounce::ZeroBounce;

let zb = ZeroBounce::new("your_api_key");
let activity = zb.get_activity_data("valid@example.com")?;
println!("Found: {}", activity.found);
if activity.found {
    println!("Active status: {}", activity.active_status);
}

Returns: ActivityData containing:

  • found: Whether activity data was found for the email
  • active_status: Active status of the email address
  • active_date: Date when the email was last active

Email Validation Methods

validate_email

Validate a single email address.

Arguments:

  • email: &str - The email address to validate

Example:

use zero_bounce::ZeroBounce;

let zb = ZeroBounce::new("your_api_key");
let validation = zb.validate_email("valid@example.com")?;
println!("Status: {}", validation.status);
println!("Sub status: {:?}", validation.sub_status);

Returns: ZBValidation containing:

  • address: The email address that was validated
  • status: Validation status (valid, invalid, catch-all, unknown, spamtrap, abuse, do_not_mail)
  • sub_status: Sub-status providing more details about the validation result
  • account: Account name (if available)
  • domain: Domain name
  • did_you_mean: Suggested alternative email address
  • domain_age_days: Age of the domain in days
  • smtp_provider: SMTP provider name
  • mx_found: Whether MX records were found
  • mx_record: MX record value
  • firstname: First name associated with the email (if available)
  • lastname: Last name associated with the email (if available)
  • gender: Gender associated with the email (if available)
  • country: Country associated with the email (if available)
  • region: Region associated with the email (if available)
  • city: City associated with the email (if available)
  • zipcode: Zipcode associated with the email (if available)
  • processed_at: Timestamp when the validation was processed

validate_email_and_ip

Validate an email address with an optional IP address for more accurate validation.

Arguments:

  • email: &str - The email address to validate
  • ip_address: &str - Optional IP address (can be empty string)

Example:

use zero_bounce::ZeroBounce;

let zb = ZeroBounce::new("your_api_key");
let validation = zb.validate_email_and_ip("valid@example.com", "99.110.204.1")?;
println!("Status: {}", validation.status);

Returns: ZBValidation - Same structure as validate_email

batch_validate

Validate multiple email addresses in a single API call. More efficient than validating emails one by one.

Arguments:

  • emails_and_ip_addresses: Vec<(String, String)> - Vector of tuples containing (email, ip_address) pairs. IP address can be empty string.

Example:

use zero_bounce::ZeroBounce;

let zb = ZeroBounce::new("your_api_key");
let emails_and_ips = vec![
    ("valid@example.com".to_string(), "99.110.204.1".to_string()),
    ("invalid@example.com".to_string(), "".to_string()),
];
let batch_result = zb.batch_validate(emails_and_ips)?;
println!("Email batch: {:#?}", batch_result.email_batch);

Returns: ZBBatchValidation containing:

  • email_batch: Vector of ZBValidation results for each email address

Bulk Validation Methods

Bulk validation allows you to upload a file containing multiple email addresses for validation. The process involves submitting a file, checking its status, fetching results, and optionally deleting the file.

Bulk flows use the v2 bulk API. For optional v2 get file query parameters, use bulk_validation_result_fetch_with_options / ai_scoring_result_fetch_with_options with ZBGetFileOptions (download_type, and activity_data for validation only). Use zb_download_type::PHASE_1, PHASE_2, or COMBINED for download_type. For validation sendfile only, chain .set_allow_phase_2(Some(true)) or Some(false) on ZBFile to send allow_phase_2 (omitted when None); AI scoring sendfile ignores this field.

On success, bulk_validation_result_fetch / ai_scoring_result_fetch return ZBBulkResponse::Content with the file bytes. Non-success HTTP statuses and JSON error bodies (including some HTTP 200 responses with "success": false) return Err(ZBError::ExplicitError(_)) with a short message, not Feedback. Use get_file_json_indicates_error / format_get_file_error_message from the crate root on a raw body string if you need to inspect responses yourself. ZBFileStatus includes optional file_phase_2_status when the API returns it.

bulk_validation_file_submit

Submit a file for bulk email validation.

Arguments:

  • zb_file: &ZBFile - A ZBFile instance containing the email addresses to validate

Example:

use zero_bounce::{ZeroBounce, ZBFile};

let zb = ZeroBounce::new("your_api_key");
let file_content = vec![
    "email1@example.com".to_string(),
    "email2@example.com".to_string(),
];
let zb_file = ZBFile::from_content(file_content)
    .set_has_header_row(false)
    .set_remove_duplicate(true);
let submit_result = zb.bulk_validation_file_submit(&zb_file)?;
println!("File ID: {:?}", submit_result.file_id);

Returns: ZBFileFeedback containing:

  • success: Whether the file submission was successful
  • message: Status message
  • file_id: Optional file ID to use for status checks and result fetching

bulk_validation_file_status_check

Check the processing status of a submitted bulk validation file.

Arguments:

  • file_id: &str - The file ID returned from bulk_validation_file_submit

Example:

use zero_bounce::ZeroBounce;

let zb = ZeroBounce::new("your_api_key");
let status = zb.bulk_validation_file_status_check("file_id_here")?;
println!("Complete percentage: {}%", status.complete_percentage);
println!("Success count: {}", status.success_count);

Returns: ZBFileStatus containing:

  • success: Whether the status check was successful
  • message: Status message
  • file_id: The file ID
  • file_name: Name of the file
  • upload_date: Date when the file was uploaded
  • file_status: Current status of the file
  • complete_percentage: Percentage of processing completed
  • return_url: URL to fetch results
  • success_count: Number of successfully processed emails
  • error_count: Number of errors encountered

bulk_validation_result_fetch

Fetch the results of a completed bulk validation file. Query parameters api_key and file_id are always sent.

Arguments:

  • file_id: &str - The file ID returned from bulk_validation_file_submit

Example:

use zero_bounce::ZeroBounce;
use zero_bounce::ZBBulkResponse;

let zb = ZeroBounce::new("your_api_key");
let result = zb.bulk_validation_result_fetch("file_id_here")?;
if let ZBBulkResponse::Content(bytes) = result {
    println!("Received {} bytes", bytes.len());
}

Returns: Ok(ZBBulkResponse::Content(bytes)) when the response is a successful file download. JSON or JSON-shaped error responses (including some HTTP 200 cases) are Err(ZBError::ExplicitError(_)).

bulk_validation_result_fetch_with_options

Same as bulk_validation_result_fetch, plus optional v2 query parameters.

Arguments:

  • file_id: &str
  • options: &ZBGetFileOptions — set download_type and/or activity_data (Some(true) / Some(false)).
use zero_bounce::{ZeroBounce, ZBGetFileOptions, zb_download_type};

let zb = ZeroBounce::new("your_api_key");
let mut opts = ZBGetFileOptions::default();
opts.download_type = Some(zb_download_type::COMBINED.to_string());
opts.activity_data = Some(true);
let result = zb.bulk_validation_result_fetch_with_options("file_id_here", &opts)?;

bulk_validation_result_delete

Delete a bulk validation result file from the ZeroBounce servers.

Arguments:

  • file_id: &str - The file ID returned from bulk_validation_file_submit

Example:

use zero_bounce::ZeroBounce;

let zb = ZeroBounce::new("your_api_key");
let delete_result = zb.bulk_validation_result_delete("file_id_here")?;
println!("Delete successful: {}", delete_result.success);

Returns: ZBFileFeedback containing:

  • success: Whether the deletion was successful
  • message: Status message

AI Scoring Methods

AI Scoring allows you to upload a file containing email addresses to get AI-powered quality scores. The process is similar to bulk validation: submit a file, check status, fetch results, and optionally delete the file.

ai_scoring_file_submit

Submit a file for AI scoring analysis.

Arguments:

  • zb_file: &ZBFile - A ZBFile instance containing the email addresses to score

Example:

use zero_bounce::{ZeroBounce, ZBFile};

let zb = ZeroBounce::new("your_api_key");
let file_content = vec![
    "email1@example.com".to_string(),
    "email2@example.com".to_string(),
];
let zb_file = ZBFile::from_content(file_content)
    .set_has_header_row(false)
    .set_remove_duplicate(true);
let submit_result = zb.ai_scoring_file_submit(&zb_file)?;
println!("File ID: {:?}", submit_result.file_id);

Returns: ZBFileFeedback - Same structure as bulk_validation_file_submit

ai_scoring_file_status_check

Check the processing status of a submitted AI scoring file.

Arguments:

  • file_id: &str - The file ID returned from ai_scoring_file_submit

Example:

use zero_bounce::ZeroBounce;

let zb = ZeroBounce::new("your_api_key");
let status = zb.ai_scoring_file_status_check("file_id_here")?;
println!("Complete percentage: {}%", status.complete_percentage);

Returns: ZBFileStatus - Same structure as bulk_validation_file_status_check

ai_scoring_result_fetch

Fetch the results of a completed AI scoring file. Same success/error rules as bulk_validation_result_fetch.

Arguments:

  • file_id: &str - The file ID returned from ai_scoring_file_submit

Example:

use zero_bounce::{ZeroBounce, ZBBulkResponse};

let zb = ZeroBounce::new("your_api_key");
let result = zb.ai_scoring_result_fetch("file_id_here")?;
if let ZBBulkResponse::Content(bytes) = result {
    println!("Received {} bytes", bytes.len());
}

ai_scoring_result_fetch_with_options

Optional download_type only; activity_data on ZBGetFileOptions is not sent for scoring getfile.

use zero_bounce::{ZeroBounce, ZBGetFileOptions, zb_download_type};

let zb = ZeroBounce::new("your_api_key");
let mut opts = ZBGetFileOptions::default();
opts.download_type = Some(zb_download_type::PHASE_2.to_string());
let result = zb.ai_scoring_result_fetch_with_options("file_id_here", &opts)?;

ai_scoring_result_delete

Delete an AI scoring result file from the ZeroBounce servers.

Arguments:

  • file_id: &str - The file ID returned from ai_scoring_file_submit

Example:

use zero_bounce::ZeroBounce;

let zb = ZeroBounce::new("your_api_key");
let delete_result = zb.ai_scoring_result_delete("file_id_here")?;
println!("Delete successful: {}", delete_result.success);

Returns: ZBFileFeedback - Same structure as bulk_validation_result_delete

Development

Run tests with Docker

From the sdk-docs/ folder in the SDKs monorepo:

cd sdk-docs
docker compose build rust
docker compose run --rm rust

Local setup and tests

# install
sudo apt update
sudo apt install cargo rustc rustup
rustup update
rustup default stable
# run tests
cargo test
cargo test find_email_v2
cargo test --release

# output
running 83 tests
test bulk::ai_scoring::test_ai_scoring_delete_not_ok ... ok
test bulk::ai_scoring::test_ai_scoring_delete_invalid_json ... ok
...
test result: ok. 83 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 5.42s
# run examples
# WARNING: examples use live server, will consume credits
cp .env.example .env
# Edit .env and set ZEROBOUNCE_API_KEY=your_api_key_here
cargo run --example # list of available examples
cargo run --example domain_search_v2

Warmup API

The Warmup API is a separate product. It has its own host, its own team-scoped key, and its own client; your validation key will not work with it.

use zero_bounce::{OnboardingModel, ZeroBounceWarmup};

let warmup = ZeroBounceWarmup::new("<YOUR_WARMUP_API_KEY>")?;

let accounts = warmup.list_sending_accounts()?;
let progress = warmup.get_progress_today()?;
let csv = warmup.download_seeds()?;            // CSV text, columns seed,provider

Add a from-address you run yourself, with one of the five standard engagement rules (0 Default, 1 Slow Pace, 2 Repair, 3 Boost, 4 Protect):

warmup.add_sending_account(
    "sender@example.com",
    OnboardingModel::SelfManaged,
    Some(0),
    None,
    None,
    None,
)?;

A custom engagement rule can be changed only once every seven days; inside that window the API answers 429.

warmup.create_custom_engagement("sender@example.com", 20, 20, 35)?;  // reply, important, click %

check_domain_dmarc takes an email address, not a domain — the live API rejects a bare domain even though the docs describe one:

let dmarc = warmup.check_domain_dmarc("sender@example.com", None)?;

Every documented empty success (204, or an empty 200) comes back as Ok(None). Failures are ZBError::ApiError, whose status is reachable through ZBError::status_code(). Nothing is stored by test_smtp_configuration, and the credentials you pass it are masked out of any error it raises.

Live API suite

cargo test never touches the network: the live suite is behind the live cargo feature, so CI does not even compile it. It needs real keys, which come from the environment and are never written anywhere:

export ZEROBOUNCE_API_KEY=...          # validation API
export ZEROBOUNCE_WARMUP_API_KEY=...   # Warmup API
cargo test --features live --test live_api -- --nocapture

By default it only makes free calls: sandbox addresses, reads, and requests that are expected to fail but still prove the API accepts the payload. It checks that the credit balance did not move. Two flags opt in to more:

Flag What it adds
ZEROBOUNCE_LIVE_SPEND=1 billable calls (scoring, activity, email finder) and a bulk round trip that deletes its own job
ZEROBOUNCE_LIVE_CHANGES=1 reversible account changes — a test filter and a self-managed Warmup sending account — each undone in cleanup even when a test fails

It never creates an Inbox Placement test, sets the Inbox Placement webhook, or starts ZB-managed Warmup onboarding, because the API cannot undo any of those.

Run it by hand before every release: the offline suite proves the SDK sends what we think it sends, and only the live suite proves the API accepts it.

Publish

  1. Bump version in Cargo.toml, commit, tag (vX.Y.Z), push tag.
  2. Actions → Publish → Run workflow with that tag.

Registry: zero-bounce on crates.io

About

No description, website, or topics provided.

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages