tickstem/verify
Validate email addresses before they hit your database: syntax, MX lookup, disposable domains, and role-based inboxes.
tickstem/verify
Go SDK for Tickstem — email verification for production apps.
Checks syntax, MX records, disposable domains, and role-based prefixes before an address touches your database.
Install
go get github.com/tickstem/verify
Quick start
package main
import (
"context"
"fmt"
"log"
"os"
"github.com/tickstem/verify"
)
func main() {
client := verify.New(os.Getenv("TICKSTEM_API_KEY"))
result, err := client.Verify(context.Background(), "user@example.com")
if err != nil {
log.Fatal(err)
}
fmt.Println(result.Valid) // true if safe to store
fmt.Println(result.Disposable) // true if throwaway address
fmt.Println(result.RoleBased) // true if generic inbox (admin@, info@, ...)
fmt.Println(result.Reason) // explanation when Valid is false
}
Get your API key at app.tickstem.dev.
Usage
Create a client
// Minimal — uses https://api.tickstem.dev/v1
client := verify.New(os.Getenv("TICKSTEM_API_KEY"))
// With options
client := verify.New(apiKey,
verify.WithBaseURL("http://localhost:8080/v1"),
)
Verify an email
result, err := client.Verify(ctx, "user@example.com")
if err != nil {
if verify.IsQuotaExceeded(err) {
// monthly quota hit — upgrade at app.tickstem.dev/dashboard/billing
}
log.Fatal(err)
}
if !result.Valid {
return fmt.Errorf("email not accepted: %s", result.Reason)
}
if result.RoleBased {
// warn but don't block — some teams share an inbox
}
What gets checked
| Check | What it catches | Why it matters |
|---|---|---|
| Syntax | Malformed addresses (user@@example, missing TLD) |
Reject obviously bad input before any network call |
| MX lookup | Domains with no mail server (gmial.com, abandoned domains) |
Catch typos and dead domains that pass syntax checks |
| Disposable | Throwaway services (Mailinator, Guerrilla Mail, 200+ others) | Block single-use signups that inflate user counts and churn immediately |
| Role-based | Generic inboxes (admin@, info@, noreply@, support@, ...) |
Flag addresses shared by teams or bots — poor engagement, not tied to a real person |
No SMTP probing — the recipient mail server is never contacted.
Retrieve history
page, err := client.ListHistory(ctx, verify.ListHistoryParams{
Limit: 50,
Offset: 0,
})
for _, v := range page.Verifications {
fmt.Printf("%s valid=%v disposable=%v\n", v.Email, v.Valid, v.Disposable)
}
Error handling
result, err := client.Verify(ctx, email)
if err != nil {
if verify.IsUnauthorized(err) {
// invalid or revoked API key
}
if verify.IsQuotaExceeded(err) {
// monthly verification limit reached
}
var apiErr *verify.APIError
if errors.As(err, &apiErr) {
fmt.Println(apiErr.StatusCode, apiErr.Message)
}
}
Pricing
| Plan | Verifications/month | Price |
|---|---|---|
| Free | 500 | $0 |
| Starter | 5,000 | $12/mo |
| Pro | 50,000 | $29/mo |
| Business | 500,000 | $79/mo |
License
MIT