Go SDK

Menu

Official Go SDK for the toSend email API.

  • Package: github.com/tosend/tosend-go
  • Requirements: Go 1.21+
  • Repository: tosend/tosend-go

Installation

go get github.com/tosend/tosend-go

Quick Start

package main

import (
    "fmt"
    "log"

    "github.com/tosend/tosend-go"
)

func main() {
    client := tosend.New("tsend_your_api_key")

    resp, err := client.Send(&tosend.SendEmailRequest{
        From:    tosend.Address{Email: "hello@yourdomain.com", Name: "Your App"},
        To:      []tosend.Address{{Email: "user@example.com"}},
        Subject: "Welcome!",
        HTML:    "<h1>Hello!</h1><p>Thanks for signing up.</p>",
    })
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println("Message ID:", resp.MessageID)
}

Configuration

Simple

client := tosend.New("tsend_your_api_key")

With Options

import "time"

client := tosend.New("tsend_your_api_key",
    tosend.WithBaseURL("https://api.tosend.com"),
    tosend.WithTimeout(60 * time.Second),
)

Custom HTTP Client

httpClient := &http.Client{
    Timeout: 60 * time.Second,
    Transport: &http.Transport{
        MaxIdleConns: 10,
    },
}

client := tosend.New("tsend_your_api_key",
    tosend.WithHTTPClient(httpClient),
)

Send Email

Basic Email

resp, err := client.Send(&tosend.SendEmailRequest{
    From: tosend.Address{
        Email: "hello@yourdomain.com",
        Name:  "Your App",
    },
    To: []tosend.Address{
        {Email: "user@example.com"},
        {Email: "another@example.com", Name: "John Doe"},
    },
    Subject: "Hello!",
    HTML:    "<h1>Welcome</h1>",
    Text:    "Welcome", // optional
})

With CC, BCC, and Reply-To

resp, err := client.Send(&tosend.SendEmailRequest{
    From:    tosend.Address{Email: "hello@yourdomain.com"},
    To:      []tosend.Address{{Email: "user@example.com"}},
    CC:      []tosend.Address{{Email: "cc@example.com"}},
    BCC:     []tosend.Address{{Email: "bcc@example.com"}},
    ReplyTo: &tosend.Address{Email: "support@yourdomain.com", Name: "Support"},
    Subject: "Hello",
    HTML:    "<p>Hello World</p>",
})

With Attachments

import (
    "encoding/base64"
    "os"
)

content, _ := os.ReadFile("invoice.pdf")
encoded := base64.StdEncoding.EncodeToString(content)

resp, err := client.Send(&tosend.SendEmailRequest{
    From:    tosend.Address{Email: "hello@yourdomain.com"},
    To:      []tosend.Address{{Email: "user@example.com"}},
    Subject: "Your Invoice",
    HTML:    "<p>Please find your invoice attached.</p>",
    Attachments: []tosend.Attachment{
        {
            Type:    "application/pdf",
            Name:    "invoice.pdf",
            Content: encoded,
        },
    },
})

Batch Sending

Send multiple emails in a single request:

resp, err := client.Batch([]tosend.SendEmailRequest{
    {
        From:    tosend.Address{Email: "hello@yourdomain.com"},
        To:      []tosend.Address{{Email: "user1@example.com"}},
        Subject: "Hello User 1",
        HTML:    "<p>Welcome!</p>",
    },
    {
        From:    tosend.Address{Email: "hello@yourdomain.com"},
        To:      []tosend.Address{{Email: "user2@example.com"}},
        Subject: "Hello User 2",
        HTML:    "<p>Welcome!</p>",
    },
})

for _, result := range resp.Results {
    if result.Status == "success" {
        fmt.Println("Sent:", result.MessageID)
    } else {
        fmt.Println("Failed:", result.Message)
    }
}

Account Info

info, err := client.GetAccountInfo()
if err != nil {
    log.Fatal(err)
}

fmt.Println("Account:", info.Account.ID, info.Account.Status)
if info.Account.CreditBalance != nil { // nil = no credit limit
    fmt.Println("Credits:", *info.Account.CreditBalance)
}
fmt.Println("Rate limit:", info.Account.LimitPerSecond, "per second")

for _, domain := range info.Domains {
    fmt.Printf("%s: %s\n", domain.DomainName, domain.VerificationStatus)
}

Admin API

tosend.NewAdmin returns a separate client for the Admin API. It takes an admin key (tsend_admin_...) and returns an error for a sending key. Each call needs the matching scope on the key; a missing scope returns a *tosend.Error whose Code() is "insufficient_scope".

admin, err := tosend.NewAdmin(os.Getenv("TOSEND_ADMIN_KEY"))
if err != nil {
    log.Fatal(err)
}

// Act on one of your client teams (sends X-Account-Id)
client := admin.ForAccount(4203)

domain, err := client.CreateDomain("client.example.com")
detail, err := client.GetDomain(domain.ID)
fmt.Println(detail.DNSRecords.DKIM.Content) // show these records to your client

// Needs api_keys:write and emails:send
key, err := client.CreateSendingKey("Client: Acme Corp", "")
fmt.Println(key.APIKey) // returned once, store it now

// Needs emails:send
_, err = client.Send(&tosend.SendEmailRequest{
    From:    tosend.Address{Email: "hello@client.example.com"},
    To:      []tosend.Address{{Email: "user@example.com"}},
    Subject: "Hi",
    HTML:    "<p>Hello</p>",
})

Also available: GetInfo, ListDomains, DeleteDomain, ListEmails, GetEmail, ListSuppressions, DeleteSuppression, ListWebhooks, CreateWebhook, UpdateWebhook, DeleteWebhook, ListSendingKeys, DeleteSendingKey, ListTeams, CreateTeam, UpdateTeam and Batch. List methods take paging parameters and return a *tosend.Page[T] with Data, Total, Page and PerPage.

Error Handling

resp, err := client.Send(&tosend.SendEmailRequest{
    From:    tosend.Address{Email: "hello@yourdomain.com"},
    To:      []tosend.Address{{Email: "user@example.com"}},
    Subject: "Hello",
    HTML:    "<p>Hello</p>",
})

if err != nil {
    if apiErr, ok := err.(*tosend.Error); ok {
        fmt.Println("Error:", apiErr.Message)
        fmt.Println("Status:", apiErr.StatusCode)
        fmt.Println("Type:", apiErr.ErrorType)   // often empty; branch on StatusCode
        fmt.Println("Details:", apiErr.Errors)    // map[string]any
        fmt.Println("Code:", apiErr.Code())       // e.g. "insufficient_scope"
    } else {
        fmt.Println("Error:", err)
    }
    return
}

fmt.Println("Sent:", resp.MessageID)