Email verification infrastructure for CI pipelines and AI agents.
Send a verification email. Catch it at the edge. Get email.OTP and email.MagicLink back — auto-extracted, no regex, no Docker, no signup.
email, err := client.WaitForLatest(ctx, inbox, nil)
email.OTP // "123456" — auto-extracted
email.MagicLink // "https://..." — no regex neededDocumentation · GitHub · Status
go get github.com/zerodrop-dev/zerodrop-goZero dependencies — stdlib only. Go 1.21+.
package main
import (
"context"
"fmt"
zerodrop "github.com/zerodrop-dev/zerodrop-go"
)
func main() {
client := zerodrop.New()
inbox := client.GenerateInbox()
// → "swift-x7k29a@zerodrop-sandbox.online"
email, err := client.WaitForLatest(context.Background(), inbox, nil)
if err != nil {
panic(err)
}
fmt.Println(email.Subject) // "Reset your password"
fmt.Println(email.OTP) // "123456" — auto-extracted, no regex
fmt.Println(email.MagicLink) // "https://..." — auto-extracted
}func TestSignupEmailVerification(t *testing.T) {
client := zerodrop.New()
inbox := client.GenerateInbox()
// Trigger your app's signup flow with the inbox address...
signUp(t, inbox)
ctx := context.Background()
email, err := client.WaitForLatest(ctx, inbox, &zerodrop.Options{
Timeout: 15 * time.Second,
})
if err != nil {
t.Fatalf("no verification email: %v", err)
}
if email.OTP == "" {
t.Fatal("expected OTP in verification email")
}
// Continue the flow with email.OTP...
verify(t, inbox, email.OTP)
}WaitForLatest uses Server-Sent Events by default. Emails arrive in under a second instead of waiting for the next poll. Polling fallback is automatic.
// Force polling mode if needed
email, err := client.WaitForLatest(ctx, inbox, &zerodrop.Options{
DisableSSE: true,
})Filter by sender, subject, body, or extracted fields when multiple emails land in the same inbox:
email, err := client.WaitForLatest(ctx, inbox, &zerodrop.Options{
Timeout: 15 * time.Second,
Filter: &zerodrop.Filter{
From: "noreply@yourapp.com",
Subject: "Verify",
HasOTP: zerodrop.Bool(true),
},
})All string filters are case-insensitive partial matches.
ZeroDrop extracts OTP codes and magic links at Cloudflare's edge before emails reach your test. No regex required.
email.OTP // "123456" — 4-8 digit verification code
email.MagicLink // "https://app.com/verify?token=abc" — verification/reset link
email.Body // Full plain-text body if you need itBoth fields are empty strings if not detected.
GenerateInbox runs locally — no network request, no throttling:
// Safe to run in parallel — each test gets an isolated inbox
func TestParallelSignups(t *testing.T) {
t.Parallel()
client := zerodrop.New()
for i := 0; i < 50; i++ {
i := i
t.Run(fmt.Sprintf("user-%d", i), func(t *testing.T) {
t.Parallel()
inbox := client.GenerateInbox() // unique, zero collision
// ...
})
}
}client := zerodrop.New(
zerodrop.WithAPIKey(os.Getenv("ZERODROP_API_KEY")),
)client := zerodrop.New(
zerodrop.WithBaseURL("https://your-instance.yourdomain.com"),
)| Function | Description |
|---|---|
New(opts ...ClientOption) *Client |
Create a client. No options = free sandbox mode. |
(*Client).GenerateInbox() string |
Instant inbox address. No network request. |
(*Client).FetchLatest(ctx, inbox, filter) (*Email, error) |
Latest matching email or nil. |
(*Client).WaitForLatest(ctx, inbox, opts) (*Email, error) |
Block until email arrives. SSE + polling fallback. |
Bool(v bool) *bool |
Helper for Filter.HasOTP / Filter.HasMagicLink. |
email, err := client.WaitForLatest(ctx, inbox, nil)
var timeoutErr *zerodrop.TimeoutError
if errors.As(err, &timeoutErr) {
// No email arrived — check your app is sending correctly
}
if errors.Is(err, zerodrop.ErrUnauthorized) {
// Invalid API key
}| Free | Workspace | |
|---|---|---|
| Inbox generation | ✓ | ✓ |
| OTP auto-extraction | ✓ | ✓ |
| Magic link extraction | ✓ | ✓ |
| Email filtering | ✓ | ✓ |
| SSE delivery | ✓ | ✓ |
| Email retention | 30 min | Extended |
| Custom domains | ✗ | ✓ |
| API key | ✗ | ✓ |
Get a Workspace at zerodrop.dev
MIT