Sendr Docs
SDKs

Go SDK

Official Go SDK for the Sendr email API.

Installation

go get github.com/sendr/sendr-go

Requires Go 1.21+.

Initialization

package main

import (
    "os"
    "github.com/sendr/sendr-go"
)

func main() {
    // Simple initialization
    client := sendr.New(os.Getenv("SENDR_API_KEY"))

    // With options
    client := sendr.New(
        os.Getenv("SENDR_API_KEY"),
        sendr.WithBaseURL("https://api.sendr.dev"),
        sendr.WithTimeout(30 * time.Second),
        sendr.WithMaxRetries(2),
    )
}

Emails

package main

import (
    "context"
    "fmt"
    "os"
    "github.com/sendr/sendr-go"
)

func main() {
    client := sendr.New(os.Getenv("SENDR_API_KEY"))
    ctx := context.Background()

    // Send a single email
    email, err := client.Emails.Send(ctx, sendr.SendEmailRequest{
        From:    "Acme <hello@acme.com>",
        To:      "user@example.com",
        Subject: "Welcome!",
        HTML:    "<h1>Welcome to Acme!</h1>",
    })
    if err != nil {
        panic(err)
    }
    fmt.Println(email.ID, email.Status)

    // Send to multiple recipients
    _, err = client.Emails.Send(ctx, sendr.SendEmailRequest{
        From:    "hello@acme.com",
        To:      []string{"alice@example.com", "bob@example.com"},
        Subject: "Team announcement",
        HTML:    "<p>Big news...</p>",
    })

    // Send using a template
    _, err = client.Emails.Send(ctx, sendr.SendEmailRequest{
        From:       "hello@acme.com",
        To:         "user@example.com",
        TemplateID: "tmpl_abc123",
        Variables: map[string]any{
            "name": "Alice",
            "plan": "Pro",
        },
    })

    // Batch send
    result, err := client.Emails.SendBatch(ctx, sendr.BatchEmailRequest{
        From:    "hello@acme.com",
        Subject: "Order update",
        Emails: []sendr.BatchEmailItem{
            {To: "alice@example.com", HTML: "<p>Alice, shipped!</p>"},
            {To: "bob@example.com", HTML: "<p>Bob, shipped!</p>"},
        },
    })
    for _, item := range result.Data {
        fmt.Println(item.ID, item.Status)
    }

    // Get email
    email, err = client.Emails.Get(ctx, "em_abc123")
    fmt.Println(email.Status)

    // List emails
    page, err := client.Emails.List(ctx, &sendr.ListEmailsParams{
        Limit:  25,
        Status: "delivered",
    })
    for _, e := range page.Data {
        fmt.Println(e.ID, e.Subject)
    }

    // Cancel
    err = client.Emails.Cancel(ctx, "em_abc123")
}

Domains

// Add a domain
domain, err := client.Domains.Create(ctx, "acme.com")
for _, record := range domain.DNSRecords {
    fmt.Printf("%s %s%s\n", record.Type, record.Host, record.Value)
}

// Verify
result, err := client.Domains.Verify(ctx, "dom_abc123")
fmt.Println(result.Status) // verified

// List, get, delete
client.Domains.List(ctx, nil)
client.Domains.Get(ctx, "dom_abc123")
client.Domains.Remove(ctx, "dom_abc123")

Error handling

import (
    "errors"
    "github.com/sendr/sendr-go"
)

email, err := client.Emails.Send(ctx, req)
if err != nil {
    var apiErr *sendr.APIError
    if errors.As(err, &apiErr) {
        switch apiErr.Code {
        case "unauthorized", "expired_key":
            fmt.Println("Authentication failed:", apiErr.Message)
        case "rate_limited", "daily_limit_reached", "monthly_limit_reached":
            // Back off and retry
            retryAfter := apiErr.RetryAfter
            time.Sleep(time.Duration(retryAfter) * time.Second)
        case "domain_not_verified":
            fmt.Println("Verify your sending domain first")
        default:
            fmt.Printf("API error %d (%s): %s\n", apiErr.StatusCode, apiErr.Code, apiErr.Message)
        }
    }
}

Webhook signature verification

import (
    "crypto/hmac"
    "crypto/sha256"
    "encoding/hex"
    "fmt"
)

func verifyWebhook(payload []byte, signature, secret string) bool {
    mac := hmac.New(sha256.New, []byte(secret))
    mac.Write(payload)
    expected := "sha256=" + hex.EncodeToString(mac.Sum(nil))
    return hmac.Equal([]byte(expected), []byte(signature))
}

// In your HTTP handler:
func webhookHandler(w http.ResponseWriter, r *http.Request) {
    body, _ := io.ReadAll(r.Body)
    sig := r.Header.Get("Sendr-Signature")

    if !verifyWebhook(body, sig, os.Getenv("SENDR_WEBHOOK_SECRET")) {
        http.Error(w, "Forbidden", http.StatusForbidden)
        return
    }

    // Process event...
    w.WriteHeader(http.StatusOK)
}

On this page