Help us shape the future of Go! Take the 2026 Go Developer Survey

vibemail

package module
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 27, 2026 License: MIT Imports: 11 Imported by: 0

README

VibeMail SDK for Go

Official SDK for the VibeMail transactional email API. No dependencies beyond the standard library.

go get github.com/vibemailai/vibemail-go

Send an email

package main

import (
	"context"
	"log"
	"os"

	vibemail "github.com/vibemailai/vibemail-go"
)

func main() {
	client := vibemail.New(os.Getenv("VIBEMAIL_API_KEY"))

	res, err := client.Send(context.Background(), vibemail.SendRequest{
		From:    "hello@yourdomain.com",
		To:      "ada@example.com",
		Subject: "Welcome",
		HTML:    "<p>Glad you're here.</p>",
		Text:    "Glad you're here.",
	})
	if err != nil {
		log.Fatal(err)
	}
	log.Println(res.ID, res.Status)
}

Send returns once the API has accepted the message, not once it has been delivered. Use Get to follow it.

Always send Text alongside HTML. Mail with no plain-text part is measurably more likely to be spam-foldered.

Every call takes a context.Context. Cancelling it stops the request and any pending retry.

Recipients

One message goes to one recipient. To reach several people, use Batch — it sends a separate message to each, which is also what stops your recipients from seeing one another's addresses:

res, err := client.Batch(ctx, []vibemail.SendRequest{
	{To: "ada@example.com", Subject: "Welcome", Text: "Hi Ada"},
	{To: "alan@example.com", Subject: "Welcome", Text: "Hi Alan"},
})

for _, entry := range res.Data {
	if entry.Error != "" {
		log.Printf("rejected: %s", entry.Error)
	}
}

Each entry succeeds or fails on its own. A comma-joined To returns ErrTooManyRecipients rather than delivering to just one of the addresses.

Retries and idempotency

Pass an idempotency key on anything you might retry. A repeat carrying the same key returns the original result instead of sending a second copy — which matters because a client that times out has no way of knowing whether the message went out.

res, err := client.Send(ctx, req, vibemail.WithIdempotencyKey("receipt-"+orderID))

The client retries 429 and 5xx on its own (twice by default, honouring Retry-After) and never retries a request the server rejected on its merits. Use vibemail.WithMaxRetries(0) to handle that yourself.

Scheduling

req := vibemail.SendRequest{To: "ada@example.com", Subject: "Reminder", Text: "Standup soon."}
req.ScheduleAt(time.Now().Add(2 * time.Hour))   // or req.ScheduledAt = "in 2 hours"

res, _ := client.Send(ctx, req)
client.Cancel(ctx, res.ID)                      // while it is still scheduled

Up to 30 days ahead. Once the dispatcher has claimed a message it is on its way out and can no longer be withdrawn.

Templates

templates, err := client.Templates(ctx)

client.Send(ctx, vibemail.SendRequest{
	To:        "ada@example.com",
	Template:  "welcome",
	Variables: map[string]string{"name": "Ada"},
})

Anything you set explicitly — Subject, HTML, Text — overrides the stored template.

Tracking flags

TrackOpens and TrackClicks are *bool so that an explicit false is distinguishable from "unset". Use the Bool helper:

req.TrackOpens = vibemail.Bool(false)

A plain bool would make "off" and "not specified" the same value, and the off would be silently dropped.

Errors

res, err := client.Send(ctx, req)

var apiErr *vibemail.Error
if errors.As(err, &apiErr) {
	log.Println(apiErr.StatusCode, apiErr.Detail)   // 422 "'to' and 'subject' are required"
	if apiErr.Retryable() {                          // 429 or 5xx
		log.Println("retry after", apiErr.RetryAfter)
	}
}

if errors.Is(err, vibemail.ErrTooManyRecipients) { /* ... */ }

Set a per-request deadline with the context:

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

Options

Option Default
WithBaseURL(u) https://vibemail.ai Point at a self-hosted deployment.
WithHTTPClient(h) 30s timeout Custom transport, proxy, or a test stub.
WithMaxRetries(n) 2 Applies to 429 and 5xx only.

API

Send(ctx, req, opts...) Send one message.
Batch(ctx, reqs, opts...) Send many, one recipient each.
Get(ctx, id) Status of a send.
Cancel(ctx, id) Withdraw a scheduled send.
Templates(ctx) Stored templates.

Client is safe for concurrent use.

License

MIT

Documentation

Overview

Package vibemail is the official Go SDK for the VibeMail transactional email API.

The surface here is limited to endpoints the API actually serves. An Analytics method existed in an earlier draft and returned 404 against every deployment; it is absent rather than broken, and will return when the endpoint does.

Index

Constants

View Source
const Version = "1.0.0"

Version of this SDK, reported in the User-Agent.

Variables

View Source
var ErrNoRecipient = errors.New("vibemail: To must contain a recipient address")

ErrNoRecipient is returned when To is empty.

View Source
var ErrTooManyRecipients = errors.New(
	"vibemail: To takes a single address — use Batch to send to several recipients, " +
		"since one message addressed to many would disclose the list to all of them")

ErrTooManyRecipients is returned when Send is given more than one address. The API delivers to a single recipient and derives per-domain rate limiting from it; silently taking the first would drop the rest with no error.

Functions

func Bool

func Bool(b bool) *bool

Bool returns a pointer, for setting TrackOpens and TrackClicks.

Types

type BatchResponse

type BatchResponse struct {
	Data []BatchResult `json:"data"`
}

BatchResponse holds one entry per message, in the order submitted.

type BatchResult

type BatchResult struct {
	ID     string `json:"id,omitempty"`
	Status string `json:"status"`
	Error  string `json:"error,omitempty"`
}

BatchResult is either an accepted message or the reason it was rejected.

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client talks to the VibeMail API. It is safe for concurrent use.

func New

func New(apiKey string, opts ...Option) *Client

New returns a Client for the given API key.

func (*Client) Batch

func (c *Client) Batch(ctx context.Context, emails []SendRequest, opts ...SendOption) (*BatchResponse, error)

Batch sends several messages in one request, one recipient each. Entries succeed or fail individually.

func (*Client) Cancel

func (c *Client) Cancel(ctx context.Context, id string) (*SendResponse, error)

Cancel withdraws a scheduled send, while it is still scheduled. Once the dispatcher has claimed it the message is on its way out.

func (*Client) Get

func (c *Client) Get(ctx context.Context, id string) (*SendResponse, error)

Get looks up a send by the id returned from Send.

func (*Client) Send

func (c *Client) Send(ctx context.Context, req SendRequest, opts ...SendOption) (*SendResponse, error)

Send delivers one message.

func (*Client) Templates

func (c *Client) Templates(ctx context.Context) ([]Template, error)

Templates lists the templates stored on the account.

type Error

type Error struct {
	StatusCode int
	// Detail is the API's "error" field when the body was JSON.
	Detail string
	// Body is the raw response, for anything Detail does not capture.
	Body string
	// RetryAfter is the server's requested wait on a 429, if it sent one.
	RetryAfter time.Duration
}

Error is a non-2xx response from the API.

func (*Error) Error

func (e *Error) Error() string

func (*Error) Retryable

func (e *Error) Retryable() bool

Retryable reports whether repeating the request could plausibly succeed.

type Option

type Option func(*Client)

Option configures a Client.

func WithBaseURL

func WithBaseURL(u string) Option

WithBaseURL points the client at a different deployment.

func WithHTTPClient

func WithHTTPClient(h *http.Client) Option

WithHTTPClient supplies your own *http.Client — for a custom transport, proxy, or a stub in tests. Its Timeout governs each attempt.

func WithMaxRetries

func WithMaxRetries(n int) Option

WithMaxRetries sets how many times a 429 or 5xx is retried. Zero disables retrying. Requests the server rejected on their merits are never retried.

type SendOption

type SendOption func(*sendOptions)

SendOption configures a single Send or Batch call.

func WithIdempotencyKey

func WithIdempotencyKey(key string) SendOption

WithIdempotencyKey makes a retry safe: a repeat carrying the same key returns the original result instead of sending a second copy. A client that times out cannot otherwise tell whether the message went out.

type SendRequest

type SendRequest struct {
	// To is the recipient. Exactly one — see Batch for several.
	To string `json:"to"`
	// From must be an address your account owns. Defaults to the account address.
	From string `json:"from,omitempty"`
	// Subject is required unless a Template supplies one.
	Subject string `json:"subject,omitempty"`
	Text    string `json:"text,omitempty"`
	HTML    string `json:"html,omitempty"`
	// Template is the name or id of a stored template. Explicit fields win over it.
	Template  string            `json:"template,omitempty"`
	Variables map[string]string `json:"variables,omitempty"`
	Tags      []string          `json:"tags,omitempty"`
	// TrackOpens and TrackClicks apply to HTML sends. Both default to on;
	// pointers distinguish "leave the default" from an explicit false.
	TrackOpens  *bool `json:"track_opens,omitempty"`
	TrackClicks *bool `json:"track_clicks,omitempty"`
	// ScheduledAt takes an RFC 3339 timestamp or a relative offset such as
	// "in 2 hours", up to 30 days ahead. Use ScheduleAt to set it from a time.Time.
	ScheduledAt string `json:"scheduled_at,omitempty"`
}

SendRequest is one outbound message.

func (*SendRequest) ScheduleAt

func (r *SendRequest) ScheduleAt(t time.Time)

ScheduleAt sets ScheduledAt from a time.Time, in UTC.

type SendResponse

type SendResponse struct {
	ID          string `json:"id"`
	Status      string `json:"status"`
	ScheduledAt string `json:"scheduled_at,omitempty"`
}

SendResponse is the API's acknowledgement. It means the message was accepted, not that it was delivered.

type Template

type Template struct {
	ID       int64  `json:"id"`
	Name     string `json:"name"`
	Subject  string `json:"subject"`
	HTMLBody string `json:"html_body,omitempty"`
	TextBody string `json:"text_body,omitempty"`
}

Template stored on the account.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL