# Send emails with Go

> Send email from Go with the official sendping-go module — typed request structs, context variants, and zero third-party dependencies.

The official Go module is the fastest way to send email from Go. It depends only on the standard library, sets the required `User-Agent` header for you, and retries `429`/`503` responses automatically.

One thing to get right: the module path ends in `/v5`. That suffix is mandatory (it is the Go major-version path for the v5 line) — `go get` without it resolves an old pre-v2 tag. The package name inside is `sendping`, not `v5`, so import it with an explicit alias.

## Prerequisites

1. A **verified domain** for your `from` address. ([guide](https://www.sendping.co/docs/domains/managing))
2. An **API key** (`mb_...`), read from `SENDPING_API_KEY`. ([Authentication](https://www.sendping.co/docs/authentication))
3. **Go 1.22 or newer** — that is the floor declared in the module `go.mod`.

## Install

```sh
go get github.com/shekhu10/sendping-sdks/sendping-go
```

## Send an email

Construct the client with `sendping.NewClient` and call `client.Emails.Send`. `delivered@test.sendping.co` is the delivery simulator — safe to send to while you wire things up. Do not use `example.com`: it is a blocked recipient domain and the send comes back `422`.

**main.go**

```go
package main

import (
	"errors"
	"fmt"
	"log"
	"os"

	sendping "github.com/shekhu10/sendping-sdks/sendping-go"
)

func main() {
	client := sendping.NewClient(os.Getenv("SENDPING_API_KEY"))

	sent, err := client.Emails.Send(&sendping.SendEmailRequest{
		From:    "Acme <hello@yourdomain.com>",
		To:      []string{"delivered@test.sendping.co"},
		Subject: "Hello from Go",
		Html:    "<p>Sent with the official Go module 🐹</p>",
	})
	if err != nil {
		var apiErr *sendping.SendPingError
		if errors.As(err, &apiErr) {
			log.Fatalf("SendPing %d %s: %s", apiErr.StatusCode, apiErr.Name, apiErr.Message)
		}
		log.Fatal(err)
	}

	fmt.Println("Sent email", sent.Id)
}
```

## Handling the response

A successful send returns `*sendping.CreateEmailResponse`, whose only field is `Id`. Keep it to [retrieve the email](https://www.sendping.co/docs/api/emails-get) later or to correlate [webhook](https://www.sendping.co/docs/webhooks/overview) events.

```json
{
  "id": "49a3999c-0ce1-4ea6-ab68-afcd6dc2e794"
}
```

Any non-2xx answer comes back as a `*sendping.SendPingError` carrying the `{ statusCode, name, message }` envelope. Branch on `Name` together with `StatusCode`, never on `Message` — message text is scrubbed server-side and is not a stable contract. Plan and quota rejections additionally populate `Limit`, and reputation gates populate `Reputation`; both are `nil` on an ordinary error.

```go
var apiErr *sendping.SendPingError
if errors.As(err, &apiErr) {
	switch apiErr.Name {
	case "validation_error":
		// 422 — a bad field, or 403 when the User-Agent header is missing.
	case "daily_quota_exceeded":
		if l := apiErr.Limit; l != nil {
			fmt.Printf("%s cap hit: %d/%d\n", l.Kind, l.Used, l.Limit)
		}
	}
}
```

## Context and tuning

Every method has a context-aware variant with a `WithContext` suffix, so a send can inherit the deadline of the request that triggered it.

```go
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()

sent, err := client.Emails.SendWithContext(ctx, params)
```

The exported client fields may be overridden before first use. `Timeout` bounds each attempt (default `sendping.DefaultTimeout`, 30s) and `MaxRetries` is the retry budget for `429`/`503` only (default `sendping.DefaultMaxRetries`, 2) — no other status, network error, or timeout is retried, so a send is never silently duplicated.

```go
client := sendping.NewClient(os.Getenv("SENDPING_API_KEY"))
client.Timeout = 10 * time.Second
client.MaxRetries = 3
```

> **Note:** The module always sends a non-empty `User-Agent` (`sendping-go/5.1.1`), which the API requires on every route — a request without one is rejected with `403 validation_error` before it is even authenticated. Setting `client.UserAgent = ""` falls back to that default rather than producing a client that 403s on every call.

> **Warning:** Read the `mb_` API key from the environment (or your secrets manager) and keep it server-side. Never compile it into a binary you ship to users — the key can send email as your account.

## Next steps

- See the full [Send Email API](https://www.sendping.co/docs/api/emails-send) reference for every body field (`Cc`, `Bcc`, `ReplyTo`, `Attachments`, `ScheduledAt`).
- Explore [the SDKs reference](https://www.sendping.co/docs/resources/sdks) for the other resources the module exposes.
- Prefer no dependencies at all? [Send with Go over raw HTTP](https://www.sendping.co/docs/send-with/go) uses only `net/http`.
