Production-ready Go integration examples for the BounceZero email verification API: single-address lookup with net/http, concurrent worker pool for bulk processing, Gin middleware for signup form validation, and CLI-style CSV batch verification.
| Field | Type | Description |
|---|---|---|
| classification | string | "valid" | "invalid" (binary verdict) |
| score | int | 0-100 confidence score |
| is_deliverable | bool | true when the address is safe to send to |
| risk_level | string | "low" | "medium" | "high" (catch-all valids are medium) |
| checks.not_disposable | bool | false if the domain is a known disposable provider |
| metadata.internal_classification | string | detail behind the verdict: verified, likely_valid, catch_all, invalid, risky, unknown, disposable, spamtrap, error |
| metadata.refunded | bool | true when the address could not be verified; the credit is auto-refunded |
net/httpNo external dependencies. Uses Go’s standard library.
package main
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"os"
"time"
)
type VerifyResult struct {
Email string `json:"email"`
Score int `json:"score"`
Classification string `json:"classification"` // "valid" | "invalid"
IsDeliverable bool `json:"is_deliverable"`
RiskLevel string `json:"risk_level"`
Checks struct {
NotDisposable *bool `json:"not_disposable"`
} `json:"checks"`
Metadata struct {
InternalClassification string `json:"internal_classification"`
Refunded bool `json:"refunded"`
CatchAllUnresolved bool `json:"catch_all_unresolved"`
} `json:"metadata"`
}
var httpClient = &http.Client{Timeout: 30 * time.Second}
func VerifyEmail(email, apiKey string) (*VerifyResult, error) {
endpoint := "https://api.bouncezero.io/api/v1/verify"
payload, _ := json.Marshal(map[string]string{"email": email})
req, err := http.NewRequest("POST", endpoint, bytes.NewReader(payload))
if err != nil {
return nil, err
}
req.Header.Set("X-API-Key", apiKey)
req.Header.Set("Content-Type", "application/json")
resp, err := httpClient.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("bouncezero: HTTP %d", resp.StatusCode)
}
var result VerifyResult
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
return nil, err
}
return &result, nil
}
func main() {
apiKey := os.Getenv("BOUNCEZERO_API_KEY")
result, err := VerifyEmail("[email protected]", apiKey)
if err != nil {
fmt.Fprintf(os.Stderr, "error: %v\n", err)
os.Exit(1)
}
fmt.Printf("classification: %s | score: %d | detail: %s | refunded: %v\n",
result.Classification, result.Score,
result.Metadata.InternalClassification, result.Metadata.Refunded)
}
Verify thousands of addresses in parallel with bounded concurrency - no unbounded goroutine spawning.
package main
import (
"fmt"
"sync"
)
const numWorkers = 20
type Job struct {
Email string
}
type Result struct {
Email string
Result string
Error error
}
func worker(apiKey string, jobs <-chan Job, results chan<- Result, wg *sync.WaitGroup) {
defer wg.Done()
for job := range jobs {
v, err := VerifyEmail(job.Email, apiKey)
if err != nil {
results <- Result{Email: job.Email, Error: err}
continue
}
results <- Result{Email: job.Email, Result: v.Classification}
}
}
func VerifyBatch(emails []string, apiKey string) []Result {
jobs := make(chan Job, len(emails))
results := make(chan Result, len(emails))
var wg sync.WaitGroup
for i := 0; i < numWorkers; i++ {
wg.Add(1)
go worker(apiKey, jobs, results, &wg)
}
for _, email := range emails {
jobs <- Job{Email: email}
}
close(jobs)
go func() {
wg.Wait()
close(results)
}()
var out []Result
for r := range results {
out = append(out, r)
}
return out
}
func main() {
emails := []string{"[email protected]", "[email protected]", "invalid@"}
apiKey := "YOUR_API_KEY"
results := VerifyBatch(emails, apiKey)
for _, r := range results {
if r.Error != nil {
fmt.Printf("ERROR %s: %v\n", r.Email, r.Error)
} else {
fmt.Printf("%-35s %s\n", r.Email, r.Result)
}
}
}
Fail-open pattern: if the API is unavailable, the request proceeds rather than blocking legitimate users.
package main
import (
"net/http"
"os"
"github.com/gin-gonic/gin"
)
func EmailVerificationMiddleware() gin.HandlerFunc {
apiKey := os.Getenv("BOUNCEZERO_API_KEY")
return func(c *gin.Context) {
var body struct {
Email string `json:"email" binding:"required,email"`
}
if err := c.ShouldBindJSON(&body); err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "invalid request"})
return
}
result, err := VerifyEmail(body.Email, apiKey)
if err != nil {
// fail-open: API unreachable > allow the request
c.Set("email_verified", false)
c.Next()
return
}
// refunded = could not be verified; fail open on those instead of blocking
if result.Classification == "invalid" && !result.Metadata.Refunded {
c.AbortWithStatusJSON(http.StatusUnprocessableEntity, gin.H{
"error": "invalid_email",
"message": "Please use a valid work email address.",
})
return
}
c.Set("email", body.Email)
c.Set("email_verified", true)
c.Next()
}
}
func main() {
r := gin.Default()
r.POST("/signup", EmailVerificationMiddleware(), func(c *gin.Context) {
email, _ := c.Get("email")
c.JSON(http.StatusOK, gin.H{"status": "ok", "email": email})
})
r.Run(":8080")
}
New to verification? Start with the complete email verification guide.
Use the standard net/http package to POST {"email": "..."} to https://api.bouncezero.io/api/v1/verify with your API key in the X-API-Key header. Unmarshal the JSON response into a struct and check the classification field (valid or invalid). No external libraries required.
Use a worker pool with goroutines and buffered channels. Create a jobs channel, launch N worker goroutines (10-20 is typical for I/O-bound API calls), and fan out addresses into the jobs channel. Each worker calls the API and sends results back. Use a WaitGroup to synchronise completion.
Sign up for a BounceZero account, grab your API key, and paste the code above. 100 free credits included - no credit card required.
Endpoints, code samples, and language guides
Drop into your stack in 5 minutes
How APIs validate in real time - endpoints + code
Integration guide: requests, async httpx, batch CSV, Flask/Django patterns
Net::HTTP, Faraday, Rails validator, Sidekiq worker, Devise hook - code examples
cURL, Guzzle, Laravel rule, WordPress registration hook - code examples
IHttpClientFactory, ASP.NET Core minimal API, IHostedService bulk queue - code examples
Continue through related topics