Spring email verification

Verify emails in Spring Boot with Verifly

Add a live email verification step to any Spring Boot app with RestTemplate or WebClient inside a @Service. Verifly is an API-first, pay-as-you-go service — call it from a bean, map the JSON verdict to a record, and even enforce it as a bean-validation constraint.

Verify one email in a @ServiceAPI
@Service
public class EmailVerifier {

    private final RestTemplate rest = new RestTemplate();

    public record Verdict(String result, boolean is_valid,
                          boolean disposable, boolean role) {}

    public Verdict verify(String email) {
        HttpHeaders headers = new HttpHeaders();
        headers.setBearerAuth("vf_YOUR_KEY"); // inject from application.yml

        String url = UriComponentsBuilder
            .fromHttpUrl("https://verifly.email/api/v1/verify")
            .queryParam("email", email)
            .toUriString();

        return rest.exchange(url, HttpMethod.GET,
            new HttpEntity<>(headers), Verdict.class).getBody();
    }
}

Real-time SMTP mailbox checks

Single, batch, and async bulk verification

Disposable, role account, and catch-all detection

Pay-as-you-go credits with no subscription lock-in

Search fit

Built for Spring email verification

Use Verifly when you need a simple API, predictable pricing, and clean JSON results before emails hit your product, CRM, or campaign tool.

Verify inside a @Service before saving a user entity
Enforce deliverability as a custom @ValidEmail constraint
Clean an imported list from a batch job
Gate an async @Scheduled task so it only mails real addresses

Email verification in a Spring @Service

Spring's Hibernate-backed @Email annotation checks that an address is syntactically valid, and no more. user@dead-domain.com sails through @Email and still bounces the moment your JavaMailSender tries to deliver. The real question — does this mailbox accept mail — is answered by an SMTP handshake, which Verifly performs for you over one HTTPS call. Wrap that call in a @Service bean so the rest of your application depends on a clean interface rather than raw HTTP.

Inside the service you can use either client Spring ships. RestTemplate is the familiar synchronous choice: set a Bearer header, build the URL with UriComponentsBuilder, and let Jackson deserialize the JSON straight into a Java record. If your stack is reactive, use WebClient instead and return a Mono. Either way the response carries a result field of deliverable, undeliverable, or risky plus boolean flags for disposable, role, catch_all, and smtp, which map onto record components automatically.

Keep the key out of source: bind it from application.yml or an environment variable through @Value, never a string literal in production. Pricing is pay-as-you-go from $2 per 1,000 checks down to $0.60 per 1,000 at volume, and you can self-register for 100 free credits with no card at the autonomous register endpoint.

Enforce it as a bean-validation constraint

Because Spring already validates DTOs with Jakarta Bean Validation, you can make deliverability a first-class constraint. Define a @ValidEmail annotation backed by a ConstraintValidator that calls your EmailVerifier service, and Spring will run it automatically on any @Valid request body. Fail open inside the validator — return true on a network error — so a Verifly outage never turns your signup endpoint into a 400 machine.

A @ValidEmail ConstraintValidator
@Constraint(validatedBy = DeliverableValidator.class)
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ValidEmail {
    String message() default "Email is not deliverable";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

@Component
class DeliverableValidator implements ConstraintValidator<ValidEmail, String> {

    private final EmailVerifier verifier;
    DeliverableValidator(EmailVerifier verifier) { this.verifier = verifier; }

    @Override
    public boolean isValid(String email, ConstraintValidatorContext ctx) {
        if (email == null) return true; // let @NotNull handle emptiness
        try {
            var v = verifier.verify(email);
            return !"undeliverable".equals(v.result()) && !v.disposable();
        } catch (RestClientException e) {
            return true; // fail open on a network error
        }
    }
}

Batch-verify a list with WebClient

For cleaning a list rather than a single field, do not loop the single endpoint — POST them together to /api/v1/verify/batch. It accepts a JSON body with an emails array and returns a results array in the same order. WebClient handles this cleanly: post the body, deserialize into a record, and stream the results down to the deliverable addresses.

Batch verification with WebClient
public record Item(String email, String result, boolean disposable) {}
public record BatchResponse(List<Item> results) {}

WebClient client = WebClient.builder()
    .baseUrl("https://verifly.email/api/v1")
    .defaultHeaders(h -> h.setBearerAuth("vf_YOUR_KEY"))
    .build();

List<String> emails = List.of("ada@example.com", "info@acme.com", "x@disposable.tld");

BatchResponse batch = client.post()
    .uri("/verify/batch")
    .bodyValue(Map.of("emails", emails))
    .retrieve()
    .bodyToMono(BatchResponse.class)
    .block();

List<String> kept = batch.results().stream()
    .filter(i -> "deliverable".equals(i.result()) && !i.disposable())
    .map(Item::email)
    .toList();

FAQ

Frequently asked questions

RestTemplate or WebClient for Verifly?

Both work. Use RestTemplate for a straightforward synchronous @Service — set a Bearer header and let Jackson map the JSON to a record. Use WebClient if your app is reactive or you want non-blocking batch calls returning a Mono. Verifly is a plain REST API, so either client fits.

How do I keep my Verifly key out of the code?

Bind it from application.yml or an environment variable with @Value("${verifly.key}") and pass it to headers.setBearerAuth(...). Never commit a literal key; the value is a Bearer secret that belongs in externalized config or a secrets manager.

Can I enforce deliverability with bean validation?

Yes. Define a @ValidEmail annotation backed by a ConstraintValidator that calls your EmailVerifier @Service. Spring runs it automatically on any @Valid DTO field, so a bad address is rejected before your controller logic ever runs.

How do I stop a Verifly outage from breaking signups?

Fail open inside the validator or service: catch RestClientException (or WebClientException) and return true / treat the address as acceptable. You only reject when Verifly positively reports undeliverable or disposable.

How do I verify a whole list of addresses?

POST them to /api/v1/verify/batch as a JSON emails array and deserialize the results array into a record list, then filter the stream on the result field. Batching is faster and cheaper than looping the single endpoint.

What does Spring email verification cost?

Pricing is pay-as-you-go from $2 per 1,000 checks down to $0.60 per 1,000 at volume, with 100 free credits when you self-register. There is no subscription. For AI agents, Verifly also exposes an MCP server at verifly.email/mcp.