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 |
|---|---|---|
| result | string | "valid" | "invalid" | "unknown" |
| is_disposable | bool | true if the domain is a known disposable provider |
| is_role_address | bool | true for info@, admin@, support@, etc. |
| catch_all_score | float64 | 0.0-1.0 - confidence the specific mailbox exists on catch-all domains |
| mx_found | bool | false means the domain has no mail server |
| free_provider | bool | true for gmail.com, outlook.com, yahoo.com, etc. |
| smtp_code | int | SMTP response code from live probe (250, 550, 421...) |
net/httpNo external dependencies. Uses Go’s standard library.
package main
import (
"encoding/json"
"fmt"
"net/http"
"net/url"
"os"
)
type VerifyResult struct {
Email string `json:"email"`
Result string `json:"result"`
IsDisposable bool `json:"is_disposable"`
IsRoleAddress bool `json:"is_role_address"`
CatchAllScore float64 `json:"catch_all_score"`
MxFound bool `json:"mx_found"`
FreeProvider bool `json:"free_provider"`
}
func VerifyEmail(email, apiKey string) (*VerifyResult, error) {
endpoint := "https://api.bouncezero.io/v1/verify"
params := url.Values{}
params.Set("email", email)
req, err := http.NewRequest("GET", endpoint+"?"+params.Encode(), nil)
if err != nil {
return nil, err
}
req.Header.Set("X-API-Key", apiKey)
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
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("result: %s | disposable: %v | catch_all_score: %.2f\n",
result.Result, result.IsDisposable, result.CatchAllScore)
}
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.Result}
}
}
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
}
if result.Result == "invalid" || result.IsDisposable {
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 call the BounceZero API with the email as a query parameter and your API key in the X-API-Key header. Unmarshal the JSON response into a struct and check the result field. 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