- 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_keyas a query parameter (ZeroBounce API contract). Do not log full request URLs or enable payload debug logging in production.
This SDK contains methods for interacting easily with ZeroBounce API.
More information about ZeroBounce you can find in the official documentation.
This SDK is built using the Java 21 version.
You can install ZeroBounceSDK by adding the dependency to your pom.xml file:
<dependency>
<groupId>com.zerobounce.java</groupId>
<artifactId>zerobouncesdk</artifactId>
<version><latest_version></version>
</dependency>- Build the JAR file for the SDK project.
- Make sure there's no other JAR located in the maven cache file. On my machine, it is located here:
~/.m2/repository/com/zerobounce/java/zerobouncesdk/ - Run the following command from the root of the project:
mvn org.apache.maven.plugins:maven-install-plugin:2.3.1:install-file \ -Dfile=zero-bounce-sdk/out/artifacts/zerobouncesdk_jar/zerobouncesdk.jar \ -DgroupId=com.zerobounce.java \ -DartifactId=zerobouncesdk \ -Dversion=<latest_version> \ -Dpackaging=jar \ -DlocalRepositoryPath=local-libs
- Run
mvn clean dependency:purge-local-repositoryin the Sample project. - Run
mvn compilein the Sample project. - Rebuild the Sample project.
- Run & enjoy!
We highly recommend you use the latest version available on Maven. However, if you plan on bundling the repository version of the SDK in your project, then here's what you need to do:
- Create a folder named local-libs in the root of your project, that will act as a "local" repository.
- In your
pom.xmlfile paste the following code that will use a "local" repository:<repositories> <repository> <id>local-repo</id> <name>Local Repo</name> <url>file://${project.basedir}/local-libs</url> </repository> </repositories>
- Inside the
<dependencies></dependencies>block, paste the following code:<dependency> <groupId>com.zerobounce.java</groupId> <artifactId>zerobouncesdk</artifactId> <version><latest_version></version> </dependency>
- Follow steps 1-5 from the How to use the sample project above.
- Rebuild the project.
- Enjoy!
- Be sure to set the autoReleaseAfterClose field to false in the
pom.xmlfile of the zero-bounce-sdk if you don't want the artifact to be automatically deployed on Maven Central. - Use the command:
mvn --no-transfer-progress --batch-mode -Dgpg.passphrase=<YOUR_PASSPHRASE> clean deploy -Preleasefrom the zero-bounce-sdk folder.
The JavaFX sample at the repository root (pom.xml, com.zerobounceexample:zero-bounce-java-sdk-setup-master) depends on com.zerobounce.java:zerobouncesdk from Maven Central with a pinned <version>, not on the zero-bounce-sdk submodule. After you publish a new SDK release, bump that version in the root pom.xml so the demo matches what users install from Central. Dependabot may open a pull request for that bump; if not, update the version manually so we do not forget.
Initialize the sdk with your api key:
ZeroBounceSDK.getInstance().initialize("<YOUR_API_KEY>");ZeroBounceSDK.getInstance().initialize("<YOUR_API_KEY>", timeoutInMillis);ZeroBounceSDK.getInstance().initialize("<YOUR_API_KEY>", "<YOUR_API_BASE_URL>");The SDK is silent by default so it never emits Personally Identifiable Information (PII) unless you
explicitly opt in. To integrate the SDK with your application's logging framework, register a
ZBLogger implementation before issuing any API calls. The helper class ZBLoggers adapts
java.util.logging (JUL) out of the box:
importcom.zerobounce.ZBLoggers;
ZeroBounceSDK.setLogger(
ZBLoggers.jul(java.util.logging.Logger.getLogger("ZeroBounceSDK"))
);
// Optional: enable verbose payload logging for troubleshooting only.ZeroBounceSDK.setLogPayloads(true);Passing null to ZeroBounceSDK.setLogger(...) resets the logger to a no-op implementation, which
disables SDK logging again.
- ZBFileStatusResponse – Includes
errorReasonwhen present, andfilePhase2Status(file_phase_2_status) when the bulk API returns it (for example after optional phase 2 processing). - ZBDownloadType –
PHASE_1,PHASE_2, orCOMBINEDfor bulkgetfilequery parameterdownload_type(validation and scoring). - ZBGetFileOptions – Optional
downloadTypeandactivityDatafor validationgetFile;scoringGetFileusesdownloadTypeonly (activityDatais not sent).
Note: The snippets below print responses for demonstration purposes. Avoid logging raw API data that may contain PII in production systems.
Then you can use any of the SDK methods, for example:
ZeroBounceSDK.getInstance().validate( "<ANY_EMAIL_ADDRESS>", "<OPTIONAL_IP_ADDRESS>", newZeroBounceSDK.OnSuccessCallback<ZBValidateResponse>() { @OverridepublicvoidonSuccess(ZBValidateResponseresponse) { System.out.println("validate response=" + response.toString()); } }, newZeroBounceSDK.OnErrorCallback() { @OverridepublicvoidonError(StringerrorMessage) { System.out.println("validate error=" + errorMessage); } }); );
List<ZBValidateBatchData> emailsData = newArrayList<ZBValidateBatchData>(); emailsData.add(newZBValidateBatchData("valid@example.com", "1.1.1.1")); emailsData.add(newZBValidateBatchData("invalid@example.com", "1.1.1.1")); emailsData.add(newZBValidateBatchData("disposable@example.com", null)); ZeroBounceSDK.getInstance().validateBatch( emailsData, newZeroBounceSDK.OnSuccessCallback<ZBValidateBatchResponse>() { @OverridepublicvoidonSuccess(ZBValidateBatchResponseresponse) { System.out.println("validateBatch response=" + response.toString()); } }, newZeroBounceSDK.OnErrorCallback() { @OverridepublicvoidonError(StringerrorMessage) { System.out.println("validateBatch error=" + errorMessage); } }); );
ZeroBounceSDK.getInstance().guessFormat( "<DOMAIN_TO_TEST>", null, null, null, newZeroBounceSDK.OnSuccessCallback<ZBEmailFinderResponse>() { @OverridepublicvoidonSuccess(ZBEmailFinderResponseresponse) { System.out.println("guessFormat response=" + response.toString()); } }, newZeroBounceSDK.OnErrorCallback() { @OverridepublicvoidonError(StringerrorMessage) { System.out.println("guessFormat error=" + errorMessage); } }); );
ZeroBounceSDK.getInstance().findEmail( "<FIRST_NAME_TO_TEST>""<DOMAIN_TO_TEST>", null, null, null, newZeroBounceSDK.OnSuccessCallback<ZBFindEmailResponse>() { @OverridepublicvoidonSuccess(ZBFindEmailResponseresponse) { System.out.println("findEmail response=" + response.toString()); } }, newZeroBounceSDK.OnErrorCallback() { @OverridepublicvoidonError(StringerrorMessage) { System.out.println("findEmail error=" + errorMessage); } }); );
ZeroBounceSDK.getInstance().findEmail( "<FIRST_NAME_TO_TEST>"null, "<COMPANY_NAME_TO_TEST>", null, null, newZeroBounceSDK.OnSuccessCallback<ZBFindEmailResponse>() { @OverridepublicvoidonSuccess(ZBFindEmailResponseresponse) { System.out.println("findEmail response=" + response.toString()); } }, newZeroBounceSDK.OnErrorCallback() { @OverridepublicvoidonError(StringerrorMessage) { System.out.println("findEmail error=" + errorMessage); } }); );
ZeroBounceSDK.getInstance().findDomain( "<DOMAIN_TO_TEST>", null, newZeroBounceSDK.OnSuccessCallback<ZBFindDomainResponse>() { @OverridepublicvoidonSuccess(ZBFindDomainResponseresponse) { System.out.println("findDomain response=" + response.toString()); } }, newZeroBounceSDK.OnErrorCallback() { @OverridepublicvoidonError(StringerrorMessage) { System.out.println("findDomain error=" + errorMessage); } }); );
ZeroBounceSDK.getInstance().findDomain( null, "COMPANY_NAME_TO_TEST", newZeroBounceSDK.OnSuccessCallback<ZBFindDomainResponse>() { @OverridepublicvoidonSuccess(ZBFindDomainResponseresponse) { System.out.println("findDomain response=" + response.toString()); } }, newZeroBounceSDK.OnErrorCallback() { @OverridepublicvoidonError(StringerrorMessage) { System.out.println("findDomain error=" + errorMessage); } }); );
ZeroBounceSDK.getInstance().getCredits( newZeroBounceSDK.OnSuccessCallback<ZBCreditsResponse>() { @OverridepublicvoidonSuccess(ZBCreditsResponseresponse) { System.out.println("getCredits response=" + response.toString()); } }, newZeroBounceSDK.OnErrorCallback() { @OverridepublicvoidonError(StringerrorMessage) { System.out.println("getCredits error=" + errorMessage); } });
DatestartDate = newDate(); // The start date of when you want to view API usageDateendDate = newDate(); // The end date of when you want to view API usageZeroBounceSDK.getInstance().getApiUsage( startDate, endDate, newZeroBounceSDK.OnSuccessCallback<ZBGetApiUsageResponse>() { @OverridepublicvoidonSuccess(ZBGetApiUsageResponseresponse) { System.out.println("getApiUsage response=" + response.toString()); } }, newZeroBounceSDK.OnErrorCallback() { @OverridepublicvoidonError(StringerrorMessage) { System.out.println("getApiUsage error=" + errorMessage); } });
FilemyFile = newFile("<FILE_PATH>"); // The csv or txt fileintemailAddressColumn = 3; // The column index of the email address in the file. Index starts at 1ZeroBounceSDK.getInstance().sendFile( myFile, emailAddressColumn, null, newZeroBounceSDK.OnSuccessCallback<ZBSendFileResponse>() { @OverridepublicvoidonSuccess(ZBSendFileResponseresponse) { System.out.println("sendFile response=" + response.toString()); } }, newZeroBounceSDK.OnErrorCallback() { @OverridepublicvoidonError(StringerrorMessage) { System.out.println("sendFile error=" + errorMessage); } });
Bulk validation uses
https://bulkapi.zerobounce.net/v2. See v2 send file, v2 file status, and v2 get file.Optional multipart field
allow_phase_2(validation bulk only): useZeroBounceSDK.SendFileOptionsandsetAllowPhase2(Boolean):ZeroBounceSDK.SendFileOptionsopts = newZeroBounceSDK.SendFileOptions() .setAllowPhase2(true); ZeroBounceSDK.getInstance().sendFile( myFile, emailAddressColumn, opts, successCallback, errorCallback);
The getFile API allows users to get the validation results file for the file been submitted using sendFile API
StringfileId = "<FILE_ID>"; // The returned file ID when calling sendfile APIStringdownloadPath = "<FILE_DOWNLOAD_PATH>"; // The path where the file will be downloadedZeroBounceSDK.getInstance().getFile( fileId, downloadPath, newZeroBounceSDK.OnSuccessCallback<ZBGetFileResponse>() { @OverridepublicvoidonSuccess(ZBGetFileResponseresponse) { System.out.println("getfile response=" + response.toString()); } }, newZeroBounceSDK.OnErrorCallback() { @OverridepublicvoidonError(StringerrorMessage) { System.out.println("getfile error=" + errorMessage); } });
Optional query parameters (validation
getFileonly for activity data;scoringGetFiledoes not sendactivity_data):importcom.zerobounce.ZBDownloadType; importcom.zerobounce.ZBGetFileOptions; ZBGetFileOptionsgetOpts = newZBGetFileOptions() .setDownloadType(ZBDownloadType.COMBINED) .setActivityData(true); ZeroBounceSDK.getInstance().getFile( fileId, downloadPath, getOpts, successCallback, errorCallback); ZeroBounceSDK.getInstance().scoringGetFile( fileId, downloadPath, newZBGetFileOptions().setDownloadType(ZBDownloadType.PHASE_2), successCallback, errorCallback);
phase_2/combineddownloads apply when phase 2 was enabled for the file andfile_phase_2_statusisComplete. JSON error bodies may still use HTTP 200; the SDK surfaces them via the failure callback.StringfileId = "<FILE_ID>"; // The returned file ID when calling sendfile APIZeroBounceSDK.getInstance().fileStatus( fileId, newZeroBounceSDK.OnSuccessCallback<ZBFileStatusResponse>() { @OverridepublicvoidonSuccess(ZBFileStatusResponseresponse) { System.out.println("fileStatus response=" + response.toString()); } }, newZeroBounceSDK.OnErrorCallback() { @OverridepublicvoidonError(StringerrorMessage) { System.out.println("fileStatus error=" + errorMessage); } });
Delete the file that was submitted using sendFile API. File can be deleted only when its status is
CompleteStringfileId = "<FILE_ID>"; // The returned file ID when calling sendfile APIZeroBounceSDK.getInstance().deleteFile( fileId, newZeroBounceSDK.OnSuccessCallback<ZBDeleteFileResponse>() { @OverridepublicvoidonSuccess(ZBDeleteFileResponseresponse) { System.out.println("deleteFile response=" + response.toString()); } }, newZeroBounceSDK.OnErrorCallback() { @OverridepublicvoidonError(StringerrorMessage) { System.out.println("deleteFile error=" + errorMessage); } });
Gather insights into your subscribers’ overall email engagement. The request returns data regarding opens, clicks, forwards and unsubscribes that have taken place in the past 30, 90, 180 or 365 days.
ZeroBounceSDK.getInstance().getActivityData( "<ANY_EMAIL_ADDRESS>", newZeroBounceSDK.OnSuccessCallback<ZBActivityDataResponse>() { @OverridepublicvoidonSuccess(ZBActivityDataResponseresponse) { System.out.println("getActivityData response=" + response.toString()); } }, newZeroBounceSDK.OnErrorCallback() { @OverridepublicvoidonError(StringerrorMessage) { System.out.println("getActivityData error=" + errorMessage); } });
FilemyFile = newFile("<FILE_PATH>"); // The csv or txt fileintemailAddressColumn = 3; // The column index of the email address in the file. Index starts at 1ZeroBounceSDK.getInstance().scoringSendFile( myFile, emailAddressColumn, null, newZeroBounceSDK.OnSuccessCallback<ZBSendFileResponse>() { @OverridepublicvoidonSuccess(ZBSendFileResponseresponse) { System.out.println("scoringSendFile response=" + response.toString()); } }, newZeroBounceSDK.OnErrorCallback() { @OverridepublicvoidonError(StringerrorMessage) { System.out.println("scoringSendFile error=" + errorMessage); } });
The scoringGetFile API allows users to get the validation results file for the file been submitted using scoringSendFile API
StringfileId = "<FILE_ID>"; // The returned file ID when calling scoringSendfile APIStringdownloadPath = "<FILE_DOWNLOAD_PATH>"; // The path where the file will be downloadedZeroBounceSDK.getInstance().scoringGetFile( fileId, downloadPath, newZeroBounceSDK.OnSuccessCallback<ZBGetFileResponse>() { @OverridepublicvoidonSuccess(ZBGetFileResponseresponse) { System.out.println("scoringGetfile response=" + response.toString()); } }, newZeroBounceSDK.OnErrorCallback() { @OverridepublicvoidonError(StringerrorMessage) { System.out.println("scoringGetfile error=" + errorMessage); } });
StringfileId = "<FILE_ID>"; // The returned file ID when calling scoringSendfile APIZeroBounceSDK.getInstance().scoringFileStatus( fileId, newZeroBounceSDK.OnSuccessCallback<ZBFileStatusResponse>() { @OverridepublicvoidonSuccess(ZBFileStatusResponseresponse) { System.out.println("scoringFileStatus response=" + response.toString()); } }, newZeroBounceSDK.OnErrorCallback() { @OverridepublicvoidonError(StringerrorMessage) { System.out.println("scoringFileStatus error=" + errorMessage); } });
Deletes the file that was submitted using scoring scoringSendFile API. File can be deleted only when its status is
CompleteStringfileId = "<FILE_ID>"; // The returned file ID when calling scoringSendfile APIZeroBounceSDK.getInstance().scoringDeleteFile( fileId, newZeroBounceSDK.OnSuccessCallback<ZBDeleteFileResponse>() { @OverridepublicvoidonSuccess(ZBDeleteFileResponseresponse) { System.out.println("scoringDeleteFile response=" + response.toString()); } }, newZeroBounceSDK.OnErrorCallback() { @OverridepublicvoidonError(StringerrorMessage) { System.out.println("scoringDeleteFile error=" + errorMessage); } });
guessFormat has been deprecated. To continue using your existing code, you must migrate to findEmail or findDomain .
The change is not a simple one-to-one replacement, as the functionality has been split:
- If you were finding a person's email format, use the new
findEmail()method. - If you were only determining the domain's general email pattern, use the new
findDomain()method.
ZeroBounceSDK.getInstance().guessFormat( "<DOMAIN_TO_TEST>", null, null, null, newZeroBounceSDK.OnSuccessCallback<ZBEmailFinderResponse>() { @OverridepublicvoidonSuccess(ZBEmailFinderResponseresponse) { System.out.println("guessFormat response=" + response.toString()); } }, newZeroBounceSDK.OnErrorCallback() { @OverridepublicvoidonError(StringerrorMessage) { System.out.println("guessFormat error=" + errorMessage); } }); );
ZeroBounceSDK.getInstance().findEmail( "<FIRST_NAME_TO_TEST>""<DOMAIN_TO_TEST>", null, null, null, newZeroBounceSDK.OnSuccessCallback<ZBFindEmailResponse>() { @OverridepublicvoidonSuccess(ZBFindEmailResponseresponse) { System.out.println("findEmail response=" + response.toString()); } }, newZeroBounceSDK.OnErrorCallback() { @OverridepublicvoidonError(StringerrorMessage) { System.out.println("findEmail error=" + errorMessage); } }); );
ZeroBounceSDK.getInstance().findEmail( "<FIRST_NAME_TO_TEST>"null, "<COMPANY_NAME_TO_TEST>", null, null, newZeroBounceSDK.OnSuccessCallback<ZBFindEmailResponse>() { @OverridepublicvoidonSuccess(ZBFindEmailResponseresponse) { System.out.println("findEmail response=" + response.toString()); } }, newZeroBounceSDK.OnErrorCallback() { @OverridepublicvoidonError(StringerrorMessage) { System.out.println("findEmail error=" + errorMessage); } }); );
ZeroBounceSDK.getInstance().findDomain( "<DOMAIN_TO_TEST>", null, newZeroBounceSDK.OnSuccessCallback<ZBFindDomainResponse>() { @OverridepublicvoidonSuccess(ZBFindDomainResponseresponse) { System.out.println("findDomain response=" + response.toString()); } }, newZeroBounceSDK.OnErrorCallback() { @OverridepublicvoidonError(StringerrorMessage) { System.out.println("findDomain error=" + errorMessage); } }); );
ZeroBounceSDK.getInstance().findDomain( null, "COMPANY_NAME_TO_TEST", newZeroBounceSDK.OnSuccessCallback<ZBFindDomainResponse>() { @OverridepublicvoidonSuccess(ZBFindDomainResponseresponse) { System.out.println("findDomain response=" + response.toString()); } }, newZeroBounceSDK.OnErrorCallback() { @OverridepublicvoidonError(StringerrorMessage) { System.out.println("findDomain error=" + errorMessage); } }); );
The ZeroBounceSDK.initialize() method can now accepts an apiBaseUrl parameter.
This allows you to specify a custom base URL for the ZeroBounce API.
The existing way of initializing the SDK is still valid.
- Default Usage (No Change Required). If you don't provide a URL, the SDK will continue to use the standard ZeroBounce API endpoint:
ZeroBounceSDK.getInstance().initialize("<YOUR_API_KEY>");ZeroBounceSDK.getInstance().initialize("<YOUR_API_KEY>", timeoutInMillis);- Initialize the SDK with your API key and URL:
ZeroBounceSDK.getInstance().initialize("<YOUR_API_KEY>", "<YOUR_API_BASE_URL>");The SDK now exposes a set of predefined constants for different geographical API endpoints, allowing for more precise network routing.
You can specify a custom API base URL during initialization by using the new optional apiBaseUrl
parameter in initialize(). For convenience, the following constants are available in the
ZBConstants class:
| Constant | URL Value | Description |
|---|---|---|
API_DEFAULT_URL | https://api.zerobounce.net/v2/ | The global default endpoint. |
API_USA_URL | https://api-us.zerobounce.net/v2/ | The US-specific endpoint for lower latency in the Americas. |
API_EU_URL | https://api-eu.zerobounce.net/v2/ | The EU-specific endpoint for compliance and lower latency in Europe. |
To use the EU endpoint for initialization:
ZeroBounceSDK.getInstance().initialize("<YOUR_API_KEY>", ZBConstants.getInstance().API_EU_URL);From the sdk-docs/ folder in the SDKs monorepo:
cd sdk-docs
docker compose build java
docker compose run --rm javaYou can also build from this repository root: docker build -t zerobounce-java-sdk:test . (uses .dockerignore to exclude target/, IDE files, and local-libs).
From the zero-bounce-sdk module directory:
cd zero-bounce-sdk
mvn testOr with the Maven wrapper: ./mvnw test.
You can generate the documentation using your desired IDE or using's maven's javadoc command.
Publishing to Maven Central is done via the GitHub Actions publish workflow, triggered manually per tag. It does not run automatically on release creation.
- Version the project and create a git tag (e.g.
v1.1.6), then push the tag. - In the repo go to Actions → Publish, click Run workflow, enter the tag (e.g.
v1.1.6), and run. - The workflow runs tests and publishes to Maven Central.
If you change the OSSRH/Sonatype or signing credentials, update the repository Secrets on GitHub.
In order to be able to publish to the Nexus repository from you local machine, you'll need to do the following step: If you want to manually publish to the Nexus repository (and then release it to Maven Central), you should:
- Import the GPG key to your local machine (see below)
- Set the autoReleaseAfterClose inside the zero-bounce-sdk's
pom.xmlto false. - Run the following command:
# For publishing to the staging repository mvn --no-transfer-progress --batch-mode -Dgpg.passphrase=<YOUR_PASSPHRASE> clean deploy -Prelease
You should then go to the Nexus Sonatype, login and then open Staging Repositories and click on Refresh. Here you'll see the artifact you just uploaded. In order to publish it, you have to close it and then release it. These actions will take a few minutes to complete. After releasing the artifact, it will take:
- a few hours before you can see it on the Maven Repository and on the Sonatype Search
- 1-3 days before you can see it on the MVN Repository
Export the keys:
gpg --list-keys # In order to obtain the key hash for the next step gpg --export -a <LAST_8_DIGITS>> public.key gpg --export-secret-key -a <LAST_8_DIGITS>> private key
Import the keys:
gpg --import public.key gpg --import private.key
Check that the new keys are imported:
gpg --list-keys gpg --list-secret-keys
- Bump
sdk.versioninzero-bounce-sdk/pom.xml, commit, tag (vX.Y.Z), push tag. - Actions → Publish → Run workflow with that tag.
Registry: com.zerobounce.java:zerobouncesdk on Maven Central