Sendery
Sendery

Language SDKs

Go

Send transactional email from Go with Sendery templates.

Install
go get github.com/sendery-co/[email protected]
Source code

Requirements

Go 1.26+. Install the SDK from a project with a go.mod file.

Set up

Publish a welcome template with name and action_url variables, and create a project API key. Store it as SENDERY_API_KEY on your server.

Shell
export SENDERY_API_KEY="your_project_api_key"

Send an email

The response contains the accepted email’s ID and Status. Set Locale to choose a template language. Omit Data when the template has no variables; it is sent as an empty JSON object.

Go
package main

import (
	"context"
	"fmt"
	"log"
	"os"

	"github.com/sendery-co/sendery-go"
)

func main() {
	client, err := sendery.NewClient(os.Getenv("SENDERY_API_KEY"))
	if err != nil {
		log.Fatal(err)
	}

	receipt, err := client.Send(context.Background(), sendery.SendEmailInput{
		To:       "[email protected]",
		Template: "welcome",
		Data: map[string]any{
			"name":       "Alex",
			"action_url": "https://example.com/start",
		},
	})
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(receipt.ID)
}

Retrieve an email

Use the returned ID to check delivery status.

Go
message, err := client.Get(context.Background(), receipt.ID)
if err != nil {
	log.Fatal(err)
}
fmt.Println(message.Status)

Retry a send

Use a key such as welcome-123 for one email, and keep the payload unchanged on retries. Prepare saves a copy of the payload. WithRetries(3) allows up to three additional attempts for temporary failures; the default is one attempt. Read the key with email.IdempotencyKey().

Go
email, err := client.Prepare(sendery.SendEmailInput{
	To:       "[email protected]",
	Template: "welcome",
	Data: map[string]any{
		"name":       "Alex",
		"action_url": "https://example.com/start",
	},
}, sendery.WithIdempotencyKey("welcome-123"), sendery.WithRetries(3))
if err != nil {
	log.Fatal(err)
}

receipt, err := email.Send(context.Background())
if err != nil {
	log.Fatal(err)
}
fmt.Println(receipt.ID)

Handle errors

Use errors.As to inspect the status, code, and field errors. RetryAfter is a *time.Duration, or nil when no delay is supplied. The example uses the prepared email from the retry example above.

Go
// Add "errors" to your imports.
receipt, err := email.Send(context.Background())
if err != nil {
	var apiError *sendery.APIError
	if errors.As(err, &apiError) {
		log.Printf("%d: %s", apiError.Status, apiError.Code)
		for field, messages := range apiError.Errors {
			log.Printf("%s: %v", field, messages)
		}
		if apiError.RetryAfter != nil {
			log.Printf("Retry after %s", *apiError.RetryAfter)
		}
	}
	log.Fatal(err)
}
fmt.Println(receipt.ID)

Set a deadline

Pass a context to Send or Get to cancel a request or limit its duration. The default HTTP timeout is 10 seconds per attempt. A context deadline also limits retry waits. Cancellation returns context.Canceled or context.DeadlineExceeded; the email may already have been accepted, so reuse its key and payload if you try again.

Go
// Add "time" to your imports. In an HTTP handler, use r.Context()
// as the parent context so requests stop when the caller disconnects.
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

receipt, err := email.Send(ctx)
if err != nil {
	log.Fatal(err)
}
fmt.Println(receipt.ID)