Email Verification API - Java 2026 | BounceZero Integration Guide
BlogDeveloper Guides

Email Verification API
Java Integration Guide 2026

Integrate BounceZero email verification into your Java application. This guide covers single-address verification with Java 11+ HttpClient, concurrent bulk processing with ExecutorService, Spring Boot bean wiring, and a fail-open signup validation pattern.

By BounceZero Team |July 2026 |6 min read

API reference

Field Value
Endpoint https://api.bouncezero.io/v1/verify
Method GET
Auth header X-API-Key: YOUR_API_KEY
Query param [email protected]
Response JSON: status, score, reason, is_disposable, is_role, is_catch_all
status values valid | invalid | risky | unknown
score 0 (certain invalid) > 100 (certain valid)
Rate limit Varies by plan; X-RateLimit-Remaining header on each response

Single address - Java 11+ HttpClient

No external dependencies. Uses java.net.http.HttpClient from the JDK.

import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.time.Duration;

public class BounceZeroClient {

    private static final String BASE_URL = "https://api.bouncezero.io/v1/verify";
    private static final String API_KEY  = System.getenv("BOUNCEZERO_API_KEY");

    private final HttpClient http = HttpClient.newBuilder()
        .connectTimeout(Duration.ofSeconds(10))
        .build();

    public VerifyResult verify(String email) throws Exception {
        String encoded = URLEncoder.encode(email, StandardCharsets.UTF_8);
        HttpRequest req = HttpRequest.newBuilder()
            .uri(URI.create(BASE_URL + "?email=" + encoded))
            .header("X-API-Key", API_KEY)
            .GET()
            .timeout(Duration.ofSeconds(15))
            .build();

        HttpResponse<String> res = http.send(req, HttpResponse.BodyHandlers.ofString());

        if (res.statusCode() != 200) {
            throw new RuntimeException("BounceZero API error: " + res.statusCode());
        }
        return VerifyResult.fromJson(res.body());
    }
}

public record VerifyResult(
    String status,   // "valid" | "invalid" | "risky" | "unknown"
    int    score,    // 0-100
    String reason,
    boolean isDisposable,
    boolean isRole,
    boolean isCatchAll
) {
    public static VerifyResult fromJson(String json) {
        // Use Jackson, Gson, or org.json - pattern shown with simple parsing
        // Example using Jackson ObjectMapper (add com.fasterxml.jackson.core:jackson-databind):
        // ObjectMapper mapper = new ObjectMapper();
        // return mapper.readValue(json, VerifyResult.class);
        throw new UnsupportedOperationException("wire your JSON library here");
    }
}

Bulk list - ExecutorService with bounded concurrency

Process large lists with a fixed thread pool. Adjust THREADS to match your plan’s rate limit.

import java.util.*;
import java.util.concurrent.*;

public class BulkVerifier {

    private static final int THREADS = 5; // adjust to your rate limit

    public Map<String, VerifyResult> verifyAll(List<String> emails) throws Exception {
        BounceZeroClient client = new BounceZeroClient();
        ExecutorService pool = Executors.newFixedThreadPool(THREADS);
        Map<String, Future<VerifyResult>> futures = new LinkedHashMap<>();

        for (String email : emails) {
            futures.put(email, pool.submit(() -> client.verify(email)));
        }

        pool.shutdown();
        pool.awaitTermination(10, TimeUnit.MINUTES);

        Map<String, VerifyResult> results = new LinkedHashMap<>();
        for (Map.Entry<String, Future<VerifyResult>> entry : futures.entrySet()) {
            try {
                results.put(entry.getKey(), entry.getValue().get());
            } catch (ExecutionException e) {
                // fail-open: treat API errors as unknown
                System.err.println("Error verifying " + entry.getKey() + ": " + e.getCause().getMessage());
                results.put(entry.getKey(), new VerifyResult("unknown", 50, "api_error", false, false, false));
            }
        }
        return results;
    }
}

Spring Boot - bean wiring + signup validation

Declare a singleton BounceZeroClient bean and inject into your registration service.

// BounceZeroConfig.java
@Configuration
public class BounceZeroConfig {
    @Bean
    public BounceZeroClient bounceZeroClient() {
        return new BounceZeroClient(); // singleton - shares HttpClient connection pool
    }
}

// RegistrationService.java
@Service
public class RegistrationService {

    private final BounceZeroClient emailVerifier;

    public RegistrationService(BounceZeroClient emailVerifier) {
        this.emailVerifier = emailVerifier;
    }

    public RegistrationResult register(String email, String password) {
        VerifyResult vr;
        try {
            vr = emailVerifier.verify(email);
        } catch (Exception e) {
            // fail-open: don't block signup if verification service is unreachable
            vr = new VerifyResult("unknown", 50, "timeout", false, false, false);
        }

        if ("invalid".equals(vr.status())) {
            return RegistrationResult.rejected("Email address is invalid or does not exist.");
        }
        if (vr.isDisposable()) {
            return RegistrationResult.rejected("Disposable email addresses are not allowed.");
        }
        if ("risky".equals(vr.status())) {
            // flag for review rather than hard block
            return createAccountWithRiskyFlag(email, password);
        }

        return createAccount(email, password);
    }
}

Always fail-open

If the API times out or returns 5xx, allow the signup through. Blocking legitimate users due to a transient API issue costs more than an occasional unverified address.

Share the HttpClient

One HttpClient instance per JVM - declare as a Spring bean or static field. Creating a new instance per request wastes connection pool resources.

Cache repeat lookups

Cache verify results by email for 24h using a Caffeine or Redis cache. The same email is often submitted multiple times; caching prevents redundant API calls.

Check score, not just status

For catch-all domains, status may be ‘risky’ but score 75+. Use score thresholds rather than just status string to fine-tune acceptance policy.

New to verification? Start with the complete email verification guide.

Frequently Asked Questions

How do I verify an email address in Java?

Use Java 11+ HttpClient to call https://api.bouncezero.io/v1/[email protected] with your API key in the X-API-Key header. The response returns status (valid/invalid/risky/unknown), score (0-100), and metadata. For Spring Boot, declare a @Bean for BounceZeroClient and inject it into your registration service. Always fail-open on timeouts.

What Java HTTP client should I use?

Java 11+ built-in java.net.http.HttpClient - no external dependency. Create one shared instance (as a Spring bean or static field) with a 10-second connection timeout and 15-second request timeout. Never create a new HttpClient per request.

How do I do bulk email verification in Java?

Use ExecutorService.newFixedThreadPool(5) to run parallel verify calls. Submit each email as a Callable, collect Futures, then read results after pool.awaitTermination(). Set thread count to match your plan rate limit. For 10K+ lists, batch in groups of 1,000 with a short sleep between batches.

Start verifying emails from your Java app today.

BounceZero’s REST API returns a JSON response in under 500ms. 100 free credits - no card required.

AL

Written by

Ayoub Lebda

Founder, BounceZero - Email-infrastructure engineer

Ayoub built BounceZero's 5-stage validation pipeline, its dedicated BGP-announced IP infrastructure, and the Patroni HA PostgreSQL cluster behind every verification. Previously built high-volume email delivery infrastructure. Trained at 1337 Benguerir (École 42 network, 2019). Open-source: bgp_analyzer.

Email verification & deliverability explained

Deep-dive guides on how email verification and inbox placement work