mailtea

package module
v0.3.0 Latest Latest
Warning

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

Go to latest
Published: Sep 10, 2026 License: MIT Imports: 15 Imported by: 0

README

mailtea-go

The official Go SDK for Mailtea — a thin, typed wrapper over the REST API.

No dependencies outside the standard library. Go 1.18 or newer.

Install

go get github.com/mailtea-app/mailtea-go@v0.1.0
import "github.com/mailtea-app/mailtea-go" // package mailtea

Usage

package main

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

	"github.com/mailtea-app/mailtea-go"
)

func main() {
	client, err := mailtea.New(os.Getenv("MAILTEA_API_KEY"))
	if err != nil {
		log.Fatal(err)
	}

	ctx := context.Background()

	sent, err := client.Emails.Send(ctx, mailtea.SendEmailRequest{
		From:    "you@yourdomain.com",
		To:      []string{"recipient@example.com"},
		Subject: "Hello from Mailtea",
		HTML:    "<p>Your first email, sent with <strong>Mailtea</strong>.</p>",
	})
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(sent.ID)

	email, err := client.Emails.Get(ctx, sent.ID)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(email.Status) // queued, sent, delivered, bounced, …
}

A single message is capped at 50 recipients combined across to + cc + bcc; the API rejects a larger one rather than accepting a send that fails downstream.

Configuration

What How
API key mailtea.New("mt_pat_…"), or mailtea.New("") to read MAILTEA_API_KEY
Base URL mailtea.New(key, mailtea.WithBaseURL("http://127.0.0.1:7787")), or MAILTEA_API_BASE_URL
Transport mailtea.New(key, mailtea.WithHTTPClient(myClient)) — anything with Do(*http.Request) (*http.Response, error)

An explicit option beats the environment variable, which beats the default (https://api.mailtea.app). New returns a *mailtea.Error with Code: "missing_api_key" when there is no key at all, rather than letting the misconfiguration surface as a 401 on your first send.

Pass a custom client to add a proxy, a timeout, retries — or, in a test, to answer without a network:

client, err := mailtea.New("mt_pat_test", mailtea.WithHTTPClient(fakeDoer{}))

API

Every method takes a context.Context first and returns (result, error).

Payloads follow the REST wire format (reply_to, scheduled_at, …). The methods below marked typed take a request struct; every other method takes mailtea.Params, a map[string]interface{} of wire-format keys. Each typed struct also has an Extra mailtea.Params field whose keys are merged over the named ones, so a field the API adds tomorrow is sendable today.

Responses that this SDK does not type are mailtea.Object — a map with typed accessors (String, Int, Bool, Object, List) and Decode(&yourStruct). List endpoints return *mailtea.List (Data []Object, plus Total/Limit/ Offset/HasMore for offset pagination or NextCursor for cursor pagination).

Method Description
Emails.Send(ctx, req) typed Send a transactional email → {ID}
Emails.Batch(ctx, reqs) typed Send up to 100 emails → {Data: [{ID}]}
Emails.Get(ctx, id) Retrieve an email and its delivery status (typed *Email)
Emails.List(ctx, params) List emails → *List
Emails.Update(ctx, id, req) typed Reschedule a scheduled email
Emails.Reschedule(ctx, id, scheduledAt) Convenience wrapper over Update
Emails.Cancel(ctx, id) Cancel a scheduled email (POST …/cancel; there is no DELETE)
Emails.Analytics(ctx, params) Aggregate transactional metrics over an optional date window
Emails.Inbound.List / Get / Reply Received emails; Reply threads by construction
Emails.Inbound.Attachments.List / Get Attachments on a received email, with signed download URLs
Contacts.Create / Upsert typed Create or update a contact (the endpoint upserts)
Contacts.Update typed Change a contact's status
Contacts.List / Get / Delete Manage audience contacts
Posts.Create(ctx, req) typed Create a newsletter post (draft, or Send: true)
Posts.Send(ctx, id, req) typed Send a draft post to the audience, now or scheduled
Posts.SendTest(ctx, id, req) typed Send a [TEST] copy → {SentTo, FailedTo}
Posts.List / Get / Update / Delete Manage posts
Segments.Create / List / Get / Update / Delete Manage audience segments
Topics.Create(ctx, req) typed Create a topic definition (opt_in / opt_out)
Topics.List / Get / Update / Delete Manage topic definitions
Senders.Create / List / Get / Update / Delete Manage named From identities (email immutable)
Assets.Upload / List / Delete The publication's image library (content accepts raw []byte)
Suppressions.List / Add / Remove Manage the team-wide do-not-send list
Suppressions.Export(ctx) Export the whole list as CSV (raw string, not JSON)
Templates.Create / List / Get / Update / Delete Manage reusable email templates
Templates.Render(ctx, params) Render a spec to HTML without saving → {html, text}
Templates.Publish / Unpublish / Duplicate Template lifecycle
Templates.Versions / RestoreVersion Design history; restoring returns the template to draft
Domains.Create / List / Get / Verify / Update / Delete Manage sending domains
Domains.Tracking.Create / List / Verify / Delete CNAME tracking sub-domains under a domain
Webhooks.Create / List / Get / Update / Delete Manage outbound event subscriptions
ContactProperties.Create / List / Update / Delete Custom contact fields (team-scoped)
APIKeys.Create / List / Revoke Manage API keys (needs settings:write)
Automations.Create / List / Get / Update / Delete Automation graphs (steps + optional connections)
Automations.Validate(ctx, params) Dry-run a graph → {valid, issues}
Automations.Activate / Pause / Archive Lifecycle (cancel_runs defaults false on pause, true on archive)
Automations.Versions / Version / Metrics Stored versions and per-step funnel counts
Automations.Test(ctx, id, params) One test run against a real contact — sends real, billed email
AutomationRuns.List / Get / Cancel Inspect and cancel runs (a run pins the version it started on)
Events.Send / List Record and list custom product events
EventDefinitions.Create / List / Get / Update / Delete The event catalog (name immutable)

Emails.Send also takes Tags, custom Headers, Attachments, and ScheduledAt. Attachments carry base64 Content; set a ContentID (plus ContentType) to embed an inline image referenced by cid: in the HTML:

_, err := client.Emails.Send(ctx, mailtea.SendEmailRequest{
	From:    "you@yourdomain.com",
	To:      []string{"recipient@example.com"},
	Subject: "Your receipt",
	HTML:    `<p>Thanks!</p><img src="cid:logo" />`,
	Tags:    []mailtea.Tag{{Name: "category", Value: "receipt"}},
	Attachments: []mailtea.Attachment{
		{Filename: "receipt.pdf", Content: pdfBase64},
		{Filename: "logo.png", Content: logoBase64, ContentType: "image/png", ContentID: "logo"}, // inline
	},
})

Webhooks

Mailtea signs every outbound webhook with Standard Webhooks. VerifyWebhookSignature checks the signature and rejects replays. Pass the raw request body — not re-serialized JSON — and the endpoint's whsec_… signing secret:

func handler(w http.ResponseWriter, r *http.Request) {
	raw, err := io.ReadAll(r.Body)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	ok := mailtea.VerifyWebhookSignature(
		signingSecret, // whsec_… returned once by Webhooks.Create
		r.Header.Get("webhook-id"),
		r.Header.Get("webhook-timestamp"),
		string(raw),
		r.Header.Get("webhook-signature"),
	)
	if !ok {
		w.WriteHeader(http.StatusUnauthorized)
		return
	}
	// … handle the event
}

SignWebhook(secret, msgID, timestamp, payload) produces the same header, handy for faking deliveries in tests. VerifyWebhookSignatureAt takes the tolerance and the current time explicitly, so a test can prove an expired delivery is rejected without waiting five minutes.

Errors

Every failure is a *mailtea.Error, reachable with errors.As:

var apiErr *mailtea.Error
if errors.As(err, &apiErr) {
	log.Printf("status=%d code=%s request_id=%s: %s",
		apiErr.Status, apiErr.Code, apiErr.RequestID, apiErr.Message)
}
Field What it carries
Status HTTP status code. 0 means the fault was on this side — a missing key, an unreachable host, an undecodable body
Message The API's own error field ("Domain is not verified"), or the client-side reason
Code The API's machine-readable code, when it sends one. Branching on this survives a copy change to Message
Details The validation issue list naming the fields that failed
RequestID The response's x-request-id — quote it in a support request
Body The raw response body, verbatim

Surfacing Message is the difference between "the send failed" and "the domain isn't verified yet".

Local development

git clone https://github.com/mailtea-app/mailtea-go
cd mailtea-go
go test ./...

The tests answer from a bundled httptest mock of the Mailtea API, so they need no API key and make no network calls. One of them checks endpoint parity with the Python SDK: every /v1/… path the reference client reaches, this one must reach too.

To run against a Mailtea on your own machine:

export MAILTEA_API_KEY="mt_pat_…"
export MAILTEA_API_BASE_URL="http://127.0.0.1:7787"

License

MIT. See LICENSE.

Documentation

Overview

Package mailtea is the official Go SDK for Mailtea — a thin, typed wrapper over the REST API at https://docs.mailtea.app/docs/api-reference.

It has no dependencies outside the standard library.

client, err := mailtea.New(os.Getenv("MAILTEA_API_KEY"))
if err != nil {
    log.Fatal(err)
}

sent, err := client.Emails.Send(ctx, mailtea.SendEmailRequest{
    From:    "you@yourdomain.com",
    To:      []string{"recipient@example.com"},
    Subject: "Hello from Mailtea",
    HTML:    "<p>Your first email.</p>",
})

Every method takes a context.Context and returns (result, error). Errors from the API are *mailtea.Error, reachable with errors.As.

Index

Constants

View Source
const DefaultBaseURL = "https://api.mailtea.app"

DefaultBaseURL is the hosted Mailtea API.

View Source
const (

	// DefaultWebhookTolerance is how far the delivery's timestamp may sit from
	// now, each way, before it is treated as a replay. Five minutes, the
	// Standard Webhooks default.
	DefaultWebhookTolerance = 5 * time.Minute
)
View Source
const Version = "0.3.0"

Version is this SDK's release. It is sent on every request as `User-Agent: mailtea-go/<Version>`, which is how a support request can be traced back to the client that made it.

The mirror repo's `v<Version>` git tag IS the Go release — pkg.go.dev indexes the tag, there is no separate registry upload — so this constant and that tag must always agree.

Variables

This section is empty.

Functions

func SignWebhook

func SignWebhook(secret, msgID string, timestamp int64, payload string) string

SignWebhook signs a payload and returns the `webhook-signature` header value in Standard Webhooks form, `v1,<base64 HMAC-SHA256>`. Useful for faking Mailtea deliveries in tests.

timestamp is Unix seconds — the same value sent in `webhook-timestamp`.

func VerifyWebhookSignature

func VerifyWebhookSignature(secret, msgID, timestamp, payload, signatureHeader string) bool

VerifyWebhookSignature checks a `webhook-signature` header against the expected HMAC.

ok := mailtea.VerifyWebhookSignature(
    signingSecret,                       // whsec_… from Webhooks.Create
    r.Header.Get("webhook-id"),
    r.Header.Get("webhook-timestamp"),
    string(rawBody),                     // exact bytes received, not re-serialized
    r.Header.Get("webhook-signature"),
)

The header may carry several space-delimited `v1,<sig>` tokens — Standard Webhooks allows key rotation, and the platform may sign one delivery with both the old and the new secret — so a match against any `v1` token passes.

It returns false when the timestamp is outside DefaultWebhookTolerance of now, which is the replay protection. The comparison is constant-time, and a bad signature is a false rather than an error.

func VerifyWebhookSignatureAt

func VerifyWebhookSignatureAt(
	secret, msgID, timestamp, payload, signatureHeader string,
	tolerance time.Duration,
	now time.Time,
) bool

VerifyWebhookSignatureAt is VerifyWebhookSignature with the tolerance and the current time supplied — the injectable form, so a test can prove that an expired timestamp is rejected without sleeping for five minutes.

Types

type APIKeysService

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

APIKeysService is the `api_keys` resource. Reach it as client.APIKeys.

Requires a token with `settings:write`. A key can never be granted scopes the calling token does not already hold.

func (*APIKeysService) Create

func (s *APIKeysService) Create(ctx context.Context, params Params) (Object, error)

Create mints an API key. The `token` is returned ONCE — store it securely.

Takes name, optional permission ("full_access" or "sending_access"), and optional domain_id.

func (*APIKeysService) List

func (s *APIKeysService) List(ctx context.Context) (*List, error)

List lists API keys. Token values are never returned.

func (*APIKeysService) Revoke

func (s *APIKeysService) Revoke(ctx context.Context, id string) (Object, error)

Revoke deletes an API key by id.

type AssetsService

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

AssetsService is the `assets` resource — a publication's image library. Reach it as client.Assets.

An email or site image block needs an absolute URL, so this is how a picture that is not already in the library gets into one. Pointing an image at a host you do not control breaks the day that host moves the file.

PNG, JPEG, GIF, WebP or SVG, 5 MB per image. The bytes are checked against the declared content_type, so a mislabelled file is rejected rather than stored.

func (*AssetsService) Delete

func (s *AssetsService) Delete(ctx context.Context, id string, params Params) (Object, error)

Delete retires an asset.

The stored file is KEPT and its URL keeps resolving, so images inside already-sent emails do not break. This hides the asset from the library — it does not remove it from any email, template or page referencing it.

func (*AssetsService) List

func (s *AssetsService) List(ctx context.Context, params Params) (*List, error)

List lists the library, newest first. Filters: publication_id (required), search (file name), limit (1-200, default 100).

func (*AssetsService) Upload

func (s *AssetsService) Upload(ctx context.Context, params Params) (Object, error)

Upload puts an image in the library and returns it, including the `url` to use as an image block's src.

Takes publication_id, content, content_type and filename. `content` may be raw []byte — base64-encoded for you — or a string that is already base64:

raw, _ := os.ReadFile("hero.png")
asset, err := client.Assets.Upload(ctx, mailtea.Params{
    "publication_id": "pub_123",
    "content":        raw,
    "content_type":   "image/png",
    "filename":       "hero.png",
})
asset.String("url")

type Attachment

type Attachment struct {
	Filename    string `json:"filename"`
	Content     string `json:"content"`
	ContentType string `json:"content_type,omitempty"`
	ContentID   string `json:"content_id,omitempty"`
}

Attachment is a file sent with an email. Content is base64. Set ContentType and a ContentID to embed an inline image referenced by `cid:` in the HTML; omit ContentID for an ordinary file attachment.

type AttachmentMeta

type AttachmentMeta struct {
	Filename    string `json:"filename"`
	ContentType string `json:"content_type"`
	Size        int64  `json:"size"`
}

AttachmentMeta describes an attachment on a retrieved email. The bytes are not returned.

type AutomationRunsService

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

AutomationRunsService is the `automation_runs` resource — one contact's journey through one automation. Reach it as client.AutomationRuns.

Runs are nested under an automation and scoped to a publication. A run PINS the automation version it started on, so Get returns the graph the run is actually executing, not the live one.

func (*AutomationRunsService) Cancel

func (s *AutomationRunsService) Cancel(ctx context.Context, automationID, runID string, params Params) (Object, error)

Cancel stops one in-flight run. Requires publication_id. A cancelled run cannot be resumed. Returns the run in full detail.

func (*AutomationRunsService) Get

func (s *AutomationRunsService) Get(ctx context.Context, automationID, runID string, params Params) (Object, error)

Get retrieves one run in full. Requires publication_id. Returns the PINNED steps/connections, the per-step step_runs, and `waiting` (resume_at / waiting_event_name) — read this rather than an event ingest's resumed_runs counter to tell whether an event actually advanced the run.

func (*AutomationRunsService) List

func (s *AutomationRunsService) List(ctx context.Context, automationID string, params Params) (*List, error)

List lists an automation's runs, cursor-paginated. Filters: publication_id (required), status (one status or a []string of them, joined for you), contact_id, is_test, limit, after. List items omit the pinned graph and the step runs; use Get for those.

A Go bool renders as "true"/"false" here, which is what the server matches `is_test` against — it 400s on anything else.

type AutomationsService

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

AutomationsService is the `automations` resource — multi-step contact journeys. Reach it as client.Automations.

Automations are scoped to a publication. An automation is a graph: `steps` (each {"key", "type", "label", "config"}) plus optional `connections` (each {"from", "to", "branch"}).

`connections` is optional: omit it and the server links the steps in array order with branch "next", rooted at the trigger. A graph containing a `condition` or `wait_for_event` step cannot be inferred that way and is rejected with `connections_required_for_branching` — send its connections explicitly.

Failures come back as coded `issues[]` rather than schema errors, and for a draft/paused/archived automation they ride along informationally instead of blocking the save.

func (*AutomationsService) Activate

func (s *AutomationsService) Activate(ctx context.Context, id string, params Params) (Object, error)

Activate starts the automation so new contacts enroll. Requires publication_id. A graph with errors is refused with 422 `automation_invalid` and the blocking issues[].

func (*AutomationsService) Archive

func (s *AutomationsService) Archive(ctx context.Context, id string, params Params) (Object, error)

Archive archives the automation. Requires publication_id (query). Optional cancel_runs — it DEFAULTS TO TRUE here, the opposite of Pause, so in-flight runs exit with `automation_archived`. Returns the automation plus canceled_runs.

func (*AutomationsService) Create

func (s *AutomationsService) Create(ctx context.Context, params Params) (Object, error)

Create adds an automation. Takes publication_id, name and steps, plus optional description, connections, reentry_policy (once/once_per_window/always — once_per_window requires reentry_window_seconds), on_step_failure and validate_only. With validate_only nothing is written and an automation_validation comes back instead. New automations start as draft — Activate starts them.

func (*AutomationsService) Delete

func (s *AutomationsService) Delete(ctx context.Context, id string, params Params) (Object, error)

Delete removes an automation. Requires publication_id. Deleting an `active` automation is a 409 `automation_active` — pause or archive it first so its in-flight runs are not dropped silently.

func (*AutomationsService) Get

func (s *AutomationsService) Get(ctx context.Context, id string, params Params) (Object, error)

Get retrieves one automation with its live graph and current issues[]. Requires publication_id.

func (*AutomationsService) List

func (s *AutomationsService) List(ctx context.Context, params Params) (*List, error)

List lists automations, cursor-paginated. Filters: publication_id (required), status (draft/active/paused/archived), limit, after. List items omit steps, connections, valid and issues — use Get for the full graph.

func (*AutomationsService) Metrics

func (s *AutomationsService) Metrics(ctx context.Context, id string, params Params) (Object, error)

Metrics returns per-step funnel counts. Filters: publication_id (required), version (omit to aggregate across ALL versions), since, until (ISO 8601). Test runs are always excluded (excludes_test_runs: true). Condition steps report branches {condition_met, condition_not_met}; wait_for_event steps {event_received, timeout}.

func (*AutomationsService) Pause

func (s *AutomationsService) Pause(ctx context.Context, id string, params Params) (Object, error)

Pause stops new enrollments. Requires publication_id (query). Optional cancel_runs — it DEFAULTS TO FALSE here, so in-flight runs keep going; pass cancel_runs true to exit them. Returns the automation plus canceled_runs.

func (*AutomationsService) Test

func (s *AutomationsService) Test(ctx context.Context, id string, params Params) (Object, error)

Test runs the automation once against a real contact. publication_id is required and is sent as a query parameter; the body takes one of contact_id or email, plus optional event_properties to seed the run's `event.*` namespace.

A test run SENDS REAL, BILLED EMAIL to that inbox — it does not bypass any send gate. It is flagged is_test and excluded from Metrics. Returns 202 with the queued run.

func (*AutomationsService) Update

func (s *AutomationsService) Update(ctx context.Context, id string, params Params) (Object, error)

Update changes an automation's name, description, steps, connections, reentry_policy, reentry_window_seconds or on_step_failure. publication_id is required and is sent as a query parameter ONLY — this endpoint rejects it in the body. The graph is replaced wholesale and cuts a new version.

validate_only returns an automation_validation and writes nothing. A graph change carrying errors saves anyway while the automation is draft/paused/archived; on an `active` one it is a 422 — pause, save, then start again.

func (*AutomationsService) Validate

func (s *AutomationsService) Validate(ctx context.Context, params Params) (Object, error)

Validate dry-runs a graph without creating anything. Takes publication_id and steps, plus optional connections. Returns {"object": "automation_validation", "valid": ..., "issues": [...]}.

func (*AutomationsService) Version

func (s *AutomationsService) Version(ctx context.Context, id string, version interface{}, params Params) (Object, error)

Version retrieves one stored version, including its steps and connections. Requires publication_id. This is the graph a run of that version is pinned to — editing the automation never rewrites it.

func (*AutomationsService) Versions

func (s *AutomationsService) Versions(ctx context.Context, id string, params Params) (Object, error)

Versions lists an automation's versions, cursor-paginated. Filters: publication_id (required), limit, after. List items carry no steps/connections — use Version for a stored graph.

type BatchResponse

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

BatchResponse is what a batch send returns — one id per message, in order.

type Client

type Client struct {
	Emails            *EmailsService
	Contacts          *ContactsService
	Segments          *SegmentsService
	Topics            *TopicsService
	Posts             *PostsService
	Senders           *SendersService
	Assets            *AssetsService
	Suppressions      *SuppressionsService
	Templates         *TemplatesService
	Domains           *DomainsService
	Webhooks          *WebhooksService
	ContactProperties *ContactPropertiesService
	APIKeys           *APIKeysService
	Automations       *AutomationsService
	AutomationRuns    *AutomationRunsService
	Events            *EventsService
	EventDefinitions  *EventDefinitionsService
	// contains filtered or unexported fields
}

Client talks to one Mailtea instance with one API key. It is safe for concurrent use by multiple goroutines.

func New

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

New builds a client.

The API key is an mt_pat_… or mt_svc_… token. Pass it explicitly, or pass "" to read MAILTEA_API_KEY from the environment. With neither, New returns a *Error with Status 0 and Code "missing_api_key" — the misconfiguration is reported where it happened rather than as a 401 on the first send.

The base URL defaults to DefaultBaseURL, overridden by MAILTEA_API_BASE_URL and then by WithBaseURL.

func (*Client) BaseURL

func (c *Client) BaseURL() string

BaseURL reports the API this client talks to, after the environment and options have been applied.

type ContactPropertiesService

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

ContactPropertiesService is the `contact_properties` resource — custom contact fields. Reach it as client.ContactProperties.

Definitions are team-scoped: there is no publication_id here. Create takes key and type ("string" or "number").

func (*ContactPropertiesService) Create

func (s *ContactPropertiesService) Create(ctx context.Context, params Params) (Object, error)

Create adds a contact property definition.

func (*ContactPropertiesService) Delete

Delete removes a contact property definition.

func (*ContactPropertiesService) List

func (s *ContactPropertiesService) List(ctx context.Context, params Params) (*List, error)

List lists contact property definitions.

func (*ContactPropertiesService) Update

func (s *ContactPropertiesService) Update(ctx context.Context, id string, params Params) (Object, error)

Update changes a contact property definition.

type ContactsService

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

ContactsService is the `contacts` resource. Reach it as client.Contacts.

Audience resources are scoped to a publication — every call takes a publication_id.

func (*ContactsService) Create

func (s *ContactsService) Create(ctx context.Context, request CreateContactRequest) (Object, error)

Create adds a contact — or updates it if the email already exists in the publication, because the endpoint upserts. Upsert is the same call under the name of what it actually does.

func (*ContactsService) Delete

func (s *ContactsService) Delete(ctx context.Context, idOrEmail string, params Params) (Object, error)

Delete removes a contact. Requires publication_id.

func (*ContactsService) Get

func (s *ContactsService) Get(ctx context.Context, idOrEmail string, params Params) (Object, error)

Get retrieves one contact by id or by email address.

func (*ContactsService) List

func (s *ContactsService) List(ctx context.Context, params Params) (*List, error)

List lists contacts, cursor-paginated. Filters: publication_id (required), status (active/unsubscribed/suppressed), search (matches the email address), limit, after (a cursor from a previous next_cursor).

func (*ContactsService) Update

func (s *ContactsService) Update(ctx context.Context, idOrEmail string, request UpdateContactRequest) (Object, error)

Update changes a contact. The publication is sent in the query string as well as the body, which is what this endpoint reads.

func (*ContactsService) Upsert

func (s *ContactsService) Upsert(ctx context.Context, request CreateContactRequest) (Object, error)

Upsert creates the contact or updates it in place — an alias of Create, named for what POST /v1/contacts really does.

type CreateContactRequest

type CreateContactRequest struct {
	PublicationID string `json:"publication_id"`
	Email         string `json:"email"`
	Status        string `json:"status,omitempty"`

	// Extra carries wire fields this SDK version does not name yet.
	Extra Params `json:"-"`
}

CreateContactRequest is the body of POST /v1/contacts.

Status is one of "active", "unsubscribed" or "suppressed"; omit it and the server picks the default.

func (CreateContactRequest) MarshalJSON

func (r CreateContactRequest) MarshalJSON() ([]byte, error)

MarshalJSON merges Extra over the named fields.

type CreatePostRequest

type CreatePostRequest struct {
	PublicationID string `json:"publication_id"`
	Subject       string `json:"subject,omitempty"`
	Name          string `json:"name,omitempty"`
	Kind          string `json:"kind,omitempty"`

	HTML string `json:"html,omitempty"`
	Text string `json:"text,omitempty"`

	TemplateID string                 `json:"template_id,omitempty"`
	Variables  map[string]interface{} `json:"variables,omitempty"`

	From    string `json:"from,omitempty"`
	ReplyTo string `json:"reply_to,omitempty"`

	// Send delivers the post to the audience as part of creating it.
	Send bool `json:"send,omitempty"`
	// ScheduledAt, with Send, queues that delivery for later (ISO 8601).
	ScheduledAt string `json:"scheduled_at,omitempty"`

	// Extra carries wire fields this SDK version does not name yet.
	Extra Params `json:"-"`
}

CreatePostRequest is the body of POST /v1/posts.

Seed the post from a published server template with TemplateID + Variables, or pass inline HTML. Kind selects the post type ("newsletter" or "broadcast"). Set Send to deliver right after creating (or add ScheduledAt to schedule) — that requires the `issues:send` scope.

func (CreatePostRequest) MarshalJSON

func (r CreatePostRequest) MarshalJSON() ([]byte, error)

MarshalJSON merges Extra over the named fields.

type CreateTopicRequest

type CreateTopicRequest struct {
	PublicationID       string `json:"publication_id"`
	Name                string `json:"name"`
	DefaultSubscription string `json:"default_subscription"`
	Description         string `json:"description,omitempty"`
	Visibility          string `json:"visibility,omitempty"`

	// Extra carries wire fields this SDK version does not name yet.
	Extra Params `json:"-"`
}

CreateTopicRequest is the body of POST /v1/topics.

DefaultSubscription is required and is one of "opt_in" or "opt_out". Visibility defaults to "private"; "public" makes the topic appear on the reader preference page as its own subscription.

func (CreateTopicRequest) MarshalJSON

func (r CreateTopicRequest) MarshalJSON() ([]byte, error)

MarshalJSON merges Extra over the named fields.

type DomainClaimsService added in v0.2.0

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

DomainClaimsService covers domain claims — taking a domain back from whichever publication currently holds it. Reach it as client.Domains.Claims.

Use it when Create is refused because the host is connected to another publication: open a claim, publish the TXT record the response lists to prove you control the DNS, then Verify. On success the other team's domain is released and a fresh one is created for you.

func (*DomainClaimsService) Cancel added in v0.2.0

func (s *DomainClaimsService) Cancel(ctx context.Context, id string, params Params) (Object, error)

Cancel withdraws a pending claim. Requires publication_id.

func (*DomainClaimsService) Create added in v0.2.0

func (s *DomainClaimsService) Create(ctx context.Context, params Params) (Object, error)

Create opens a claim. Takes publication_id, name, and an optional region. The response's `records` lists the TXT record to publish.

func (*DomainClaimsService) Get added in v0.2.0

func (s *DomainClaimsService) Get(ctx context.Context, id string, params Params) (Object, error)

Get polls a claim. Requires publication_id.

func (*DomainClaimsService) Verify added in v0.2.0

func (s *DomainClaimsService) Verify(ctx context.Context, id string, params Params) (Object, error)

Verify checks the TXT record and completes the claim if it is there.

Safe to call repeatedly: a record that has not propagated yet leaves the claim pending with the same record, so nothing has to be republished. A completed claim answers with the fresh `domain` beside the claim.

type DomainsService

type DomainsService struct {

	// Tracking covers the CNAME tracking sub-domains under a domain.
	Tracking *TrackingDomainsService

	// Claims covers taking a domain back from the team that currently holds it.
	Claims *DomainClaimsService
	// contains filtered or unexported fields
}

DomainsService is the `domains` resource — email and site sending domains. Reach it as client.Domains.

Scoped to a publication. Register a domain, add the DNS `records` the response lists, then Verify it before sending from it.

func (*DomainsService) Create

func (s *DomainsService) Create(ctx context.Context, params Params) (Object, error)

Create registers a domain. The response's `records` lists the DNS records to add.

func (*DomainsService) Delete

func (s *DomainsService) Delete(ctx context.Context, id string, params Params) (Object, error)

Delete removes a domain. Requires publication_id.

func (*DomainsService) Get

func (s *DomainsService) Get(ctx context.Context, id string, params Params) (Object, error)

Get retrieves one domain. Requires publication_id.

func (*DomainsService) List

func (s *DomainsService) List(ctx context.Context, params Params) (*List, error)

List lists domains. Requires publication_id.

func (*DomainsService) Update

func (s *DomainsService) Update(ctx context.Context, id string, params Params) (Object, error)

Update changes a domain — open_tracking, click_tracking, custom_return_path and the like. publication_id travels in the query string and the body alike.

custom_return_path delegates a subdomain as the envelope sender so SPF aligns with your own domain. Mail keeps sending on the default return-path until the delegated DNS resolves.

tracking_subdomain set to nil removes a tracking subdomain: the domain's links go back to being served from the Mailtea host, and links in mail already sent point at the old hostname and stop resolving. Params reaches the encoder as given, so the nil travels as a JSON null — leaving the key out (leave the subdomain alone) and setting it to nil (remove it) are different requests. An empty string is neither; it is refused with tracking_subdomain_invalid. nil is an update-only value: a create has nothing to clear.

func (*DomainsService) Verify

func (s *DomainsService) Verify(ctx context.Context, id string, params Params) (Object, error)

Verify checks a domain's DNS records; on success its status becomes "verified".

type DroppedRecipient

type DroppedRecipient struct {
	Address string `json:"address"`
	Field   string `json:"field"`
	Reason  string `json:"reason"`
}

DroppedRecipient is an address the message did not reach, and why. To/CC/BCC are what was ASKED for; a suppressed or unusable address is filtered out of the envelope but left in those fields, so without reading this a partially delivered send looks identical to a fully delivered one.

type Email

type Email struct {
	Object  string `json:"object"`
	ID      string `json:"id"`
	From    string `json:"from"`
	To      string `json:"to"`
	CC      string `json:"cc"`
	BCC     string `json:"bcc"`
	ReplyTo string `json:"reply_to"`
	Subject string `json:"subject"`
	HTML    string `json:"html"`
	Text    string `json:"text"`

	// LastEvent is where the send got to: queued, scheduled, sent, delivered,
	// delivery_delayed, bounced, complained, failed, suppressed, canceled.
	// Reading it is how you check on a send without setting up a webhook.
	LastEvent string `json:"last_event"`
	// Status is a friendly alias of LastEvent, filled in by this SDK.
	Status string `json:"status"`

	// Error is why the send failed, in neutral words — the provider's own
	// wording is never returned. Empty on every email that has not failed.
	Error string `json:"error"`

	DroppedRecipients []DroppedRecipient `json:"dropped_recipients"`

	CreatedAt   string `json:"created_at"`
	ScheduledAt string `json:"scheduled_at"`
	FailedAt    string `json:"failed_at"`
	DelayedAt   string `json:"delayed_at"`
	OpenedAt    string `json:"opened_at"`
	OpenCount   int    `json:"open_count"`
	ClickedAt   string `json:"clicked_at"`
	ClickCount  int    `json:"click_count"`

	Tags        []Tag             `json:"tags"`
	Headers     map[string]string `json:"headers"`
	Attachments []AttachmentMeta  `json:"attachments"`
}

Email is one send, as returned by Get.

type EmailsService

type EmailsService struct {

	// Inbound covers received mail: list, get, reply, and attachments.
	Inbound *InboundService
	// contains filtered or unexported fields
}

EmailsService is the `emails` resource. Reach it as client.Emails.

func (*EmailsService) Analytics

func (s *EmailsService) Analytics(ctx context.Context, params Params) (Object, error)

Analytics aggregates transactional metrics over an optional date window: totals, delivered/bounced/open/click counts, per-status counts, and rates. Optional filters: from_date, to_date (ISO 8601), clamped like List's.

func (*EmailsService) Batch

func (s *EmailsService) Batch(ctx context.Context, requests []SendEmailRequest) (*BatchResponse, error)

Batch sends up to 100 emails in one request. The body is a bare array, which is what this endpoint takes — not an object wrapping one.

func (*EmailsService) Cancel

func (s *EmailsService) Cancel(ctx context.Context, id string) (Object, error)

Cancel stops a scheduled email before it sends.

It works only while the email is still `scheduled`. Any other status — including the `queued` of an ordinary immediate send — answers 422, so treat that as "too late to stop it" rather than as a bug. There is no DELETE on emails; cancel is this POST.

The reply is `{object, id}` and nothing more — a 2xx IS the confirmation. Call Get if you want to read the resulting `canceled` status back.

func (*EmailsService) Get

func (s *EmailsService) Get(ctx context.Context, id string) (*Email, error)

Get retrieves an email with its delivery status and tracking counters.

The id goes through url.PathEscape: a real "txemail_…" passes through untouched, and an id from somewhere less trustworthy cannot walk out of the path segment it belongs in.

func (*EmailsService) List

func (s *EmailsService) List(ctx context.Context, params Params) (*List, error)

List lists emails, most recent first. Optional filters: status, tag_name, tag_value, search (substring match on recipient/sender/subject), from_date, to_date, limit, offset.

from_date is clamped to the plan's analytics retention window — 30 days on most plans, 90 on Scale and Enterprise. A value reaching further back returns data from the start of that window rather than an error, and omitting it returns the window rather than all time.

func (*EmailsService) Reschedule

func (s *EmailsService) Reschedule(ctx context.Context, id, scheduledAt string) (Object, error)

Reschedule is Update for the one case it exists for.

func (*EmailsService) Send

Send sends one transactional email, or schedules it when ScheduledAt is set.

func (*EmailsService) Update

func (s *EmailsService) Update(ctx context.Context, id string, request UpdateEmailRequest) (Object, error)

Update changes a scheduled email (currently only scheduled_at).

type Error

type Error struct {
	// Status is the HTTP status code. Zero means the failure happened on this
	// side of the wire — a missing API key, an unreachable host, a response
	// body that was not the JSON it claimed to be — so there is no status to
	// report. Branch on it before assuming the API said anything at all.
	Status int

	// Message is the API's own `error` field ("Domain is not verified",
	// "Validation failed"), or the client-side reason when Status is 0.
	Message string

	// Code is the API's machine-readable code, when it sends one (for example
	// `marketing_plan_required` on a 402, or `template_version_not_found`).
	// Branching on Code survives a copy change to Message. Empty when absent.
	Code string

	// Details is the validation issue list the API returns alongside a 400,
	// naming the fields that failed. Nil when absent. It is decoded as
	// free-form JSON because its shape varies per endpoint; use DetailsJSON to
	// print it or json.Unmarshal it into your own type.
	Details interface{}

	// RequestID is the response's `x-request-id` header — quote it in a support
	// request and the exact call can be found.
	RequestID string

	// Body is the raw response body, kept verbatim. The parsed fields above are
	// what you branch on; this is what you log when they were not enough.
	Body string
}

Error is returned whenever the Mailtea API answers with a non-2xx status, or the client is misconfigured before a request is even attempted.

Reach it with errors.As:

var apiErr *mailtea.Error
if errors.As(err, &apiErr) && apiErr.Status == 422 {
    // too late to cancel
}

func (*Error) Error

func (e *Error) Error() string

type EventDefinitionsService

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

EventDefinitionsService is the `event_definitions` resource — the catalog of event names a publication expects, with optional property schemas. Reach it as client.EventDefinitions.

Definitions are scoped to a publication. They are documentation and tooling, not a gate: Events.Send accepts an event with no definition.

func (*EventDefinitionsService) Create

func (s *EventDefinitionsService) Create(ctx context.Context, params Params) (Object, error)

Create adds an event definition. Takes publication_id and name, plus optional description and schema_json. The name is immutable once created.

func (*EventDefinitionsService) Delete

func (s *EventDefinitionsService) Delete(ctx context.Context, id string, params Params) (Object, error)

Delete removes an event definition. Requires publication_id. Events already recorded under that name are untouched.

func (*EventDefinitionsService) Get

func (s *EventDefinitionsService) Get(ctx context.Context, id string, params Params) (Object, error)

Get retrieves one definition. Requires publication_id. Adds schema_properties and inferred_properties — the latter computed on read over the last 500 events, reporting each key's type, sample count and COVERAGE. Low coverage is the trap: a condition on a key present in 3% of events will almost never match.

func (*EventDefinitionsService) List

func (s *EventDefinitionsService) List(ctx context.Context, params Params) (*List, error)

List lists event definitions, cursor-paginated. Filters: publication_id (required), limit, after. List items carry no inferred_properties — use Get for those.

func (*EventDefinitionsService) Update

func (s *EventDefinitionsService) Update(ctx context.Context, id string, params Params) (Object, error)

Update changes a definition's description or schema_json (an explicit nil clears the schema back to free-form). publication_id is required and is sent as a query parameter ONLY. `name` is immutable — sending it is a 400 `event_name_immutable`, not a silently dropped rename.

type EventsService

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

EventsService is the `events` resource — custom product events that trigger automations and resume `wait_for_event` steps. Reach it as client.Events.

Events are scoped to a publication.

func (*EventsService) List

func (s *EventsService) List(ctx context.Context, params Params) (*List, error)

List lists recorded events, cursor-paginated. Filters: publication_id (required), name, contact_id, limit, after.

func (*EventsService) Send

func (s *EventsService) Send(ctx context.Context, params Params) (Object, error)

Send records an event for a contact. Takes publication_id, name, and exactly one of contact_id or email (both is a 400 `contact_reference_conflict`, neither a 400 `contact_reference_required`). Optional: create_contact, properties, occurred_at, idempotency_key.

create_contact is OPT-IN — without it an unresolvable address is a 404 `contact_not_found` rather than a new contact.

Returns 202 with enrolled_automations and resumed_runs. A replay of the same idempotency_key returns the ORIGINAL event id with replayed: true and always reports enrolled_automations: 0, resumed_runs: 0. Note that resumed_runs: 0 on a FRESH ingest does not prove nothing matched — a run being advanced concurrently is invisible for that instant, so read the run itself (client.AutomationRuns.Get) rather than the counter.

type HTTPDoer

type HTTPDoer interface {
	Do(req *http.Request) (*http.Response, error)
}

HTTPDoer is the slice of *http.Client this SDK uses. Supply your own to add a proxy, a timeout, retries, or — in a test — to answer without a network:

client, _ := mailtea.New("mt_pat_test", mailtea.WithHTTPClient(fake))

type InboundAttachmentsService

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

InboundAttachmentsService covers attachments on a received email. Reach it as client.Emails.Inbound.Attachments. Each returned object carries a short-lived signed download_url.

func (*InboundAttachmentsService) Get

func (s *InboundAttachmentsService) Get(ctx context.Context, id, attachmentID string) (Object, error)

Get retrieves a single inbound attachment with a signed download URL.

func (*InboundAttachmentsService) List

List lists an inbound email's attachments, each with a signed download URL.

type InboundService

type InboundService struct {

	// Attachments covers the files on a received email.
	Attachments *InboundAttachmentsService
	// contains filtered or unexported fields
}

InboundService covers inbound (received) emails. Reach it as client.Emails.Inbound.

List and retrieve mail delivered to your receiving domains, download attachments, and Reply — which threads correctly by construction and reuses the transactional send pipeline. Scoped to a publication: pass publication_id to List.

func (*InboundService) Get

func (s *InboundService) Get(ctx context.Context, id string) (Object, error)

Get retrieves a single received email, including its body, headers, and attachments.

func (*InboundService) List

func (s *InboundService) List(ctx context.Context, params Params) (*List, error)

List lists received emails in a publication, most recent first, cursor-paginated. Takes publication_id, optional limit (1-100, default 20) and cursor.

func (*InboundService) Reply

func (s *InboundService) Reply(ctx context.Context, id string, params Params) (Object, error)

Reply replies to a received email. The reply target (`to`), threading headers, and the "Re: " subject default are all server-derived — pass only the content (html/text, and optionally from, subject, cc, bcc, idempotency_key). Returns the resulting transactional email's id and status.

type List

type List struct {
	Object     string   `json:"object"`
	Data       []Object `json:"data"`
	Total      int      `json:"total"`
	Limit      int      `json:"limit"`
	Offset     int      `json:"offset"`
	HasMore    bool     `json:"has_more"`
	NextCursor string   `json:"next_cursor"`
}

List is the API's standard list envelope. Offset-paginated endpoints (emails, posts) fill Total/Limit/Offset/HasMore; cursor-paginated ones (contacts, senders, templates, automations, events, …) fill NextCursor and leave Total at zero. Data holds the rows either way.

type Object

type Object map[string]interface{}

Object is a decoded JSON response. It is a plain map, so an unfamiliar or brand-new field is still readable, with typed accessors for the common reads and Decode for pulling the whole thing into a struct of your own.

func (Object) Bool

func (o Object) Bool(key string) bool

Bool returns a boolean field, or false when the key is absent or not a bool.

func (Object) Decode

func (o Object) Decode(v interface{}) error

Decode re-encodes the object and unmarshals it into v, so a caller who wants a struct does not have to reach through the map:

var domain struct {
    ID     string `json:"id"`
    Status string `json:"status"`
}
err := created.Decode(&domain)

func (Object) Float

func (o Object) Float(key string) float64

Float returns a numeric field. JSON numbers decode to float64, so this is the lossless read; Int rounds it for counters and ids.

func (Object) Int

func (o Object) Int(key string) int

Int returns a numeric field truncated to an int, or 0 when absent.

func (Object) List

func (o Object) List(key string) []Object

List returns a nested array of objects, skipping any element that is not one.

func (Object) Object

func (o Object) Object(key string) Object

Object returns a nested object field, or nil when absent or not an object.

func (Object) String

func (o Object) String(key string) string

String returns a string field, or "" when the key is absent or not a string.

type Option

type Option func(*Client)

Option configures a Client at construction.

func WithBaseURL

func WithBaseURL(baseURL string) Option

WithBaseURL points the client at a different Mailtea — a self-hosted instance, or http://127.0.0.1:7787 in local dev. An empty string is ignored, so passing os.Getenv("MAILTEA_API_BASE_URL") is safe when the variable is unset. A trailing slash is trimmed; a path prefix is kept.

func WithHTTPClient

func WithHTTPClient(doer HTTPDoer) Option

WithHTTPClient replaces the underlying HTTP client. A nil value is ignored.

type Params

type Params map[string]interface{}

Params is a free-form wire-format payload: snake_case keys exactly as the REST API names them ("reply_to", "publication_id", "scheduled_at").

The methods this SDK types explicitly — emails.Send/Batch/Update, contacts.Create/Update, posts.Create/Send/SendTest, topics.Create — take a request struct instead. Everything else takes Params, so a field added to the API is reachable the day it ships rather than the day this SDK is re-released.

type PostsService

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

PostsService is the `posts` resource — newsletter posts and issues. Reach it as client.Posts.

func (*PostsService) Create

func (s *PostsService) Create(ctx context.Context, request CreatePostRequest) (Object, error)

Create adds a newsletter post — a draft unless Send is set.

func (*PostsService) Delete

func (s *PostsService) Delete(ctx context.Context, id string, params Params) (Object, error)

Delete removes a draft post. Sent posts cannot be deleted.

func (*PostsService) Get

func (s *PostsService) Get(ctx context.Context, id string, params Params) (Object, error)

Get retrieves a post by id.

func (*PostsService) List

func (s *PostsService) List(ctx context.Context, params Params) (*List, error)

List lists posts, most recent first, offset-paginated. Takes publication_id (required) plus optional limit, offset, status and kind.

func (*PostsService) Send

func (s *PostsService) Send(ctx context.Context, id string, request SendPostRequest) (Object, error)

Send delivers a draft post to the publication's audience — immediately, or at ScheduledAt. Requires the `issues:send` scope.

func (*PostsService) SendTest

SendTest sends a TEST copy of a post to specific recipients, to check it before subscribers see it. It renders the post exactly as a subscriber would receive it and delivers a one-shot [TEST] email — it does NOT send to the audience.

func (*PostsService) Update

func (s *PostsService) Update(ctx context.Context, id string, params Params) (Object, error)

Update changes a draft post — subject, html, text, from, reply_to, name. Sent posts are immutable.

type SegmentsService

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

SegmentsService is the `segments` resource. Reach it as client.Segments.

Audience segments are scoped to a publication — pass publication_id. To clear a nullable filter on update, set it to nil explicitly (Params{"status_filter": nil} is dropped from a query but kept in a body); omit the key to leave it unchanged.

func (*SegmentsService) Create

func (s *SegmentsService) Create(ctx context.Context, params Params) (Object, error)

Create adds a segment.

func (*SegmentsService) Delete

func (s *SegmentsService) Delete(ctx context.Context, id string, params Params) (Object, error)

Delete removes a segment. Requires publication_id.

func (*SegmentsService) Get

func (s *SegmentsService) Get(ctx context.Context, id string, params Params) (Object, error)

Get retrieves one segment. Requires publication_id.

func (*SegmentsService) List

func (s *SegmentsService) List(ctx context.Context, params Params) (*List, error)

List lists segments. Requires publication_id.

func (*SegmentsService) Update

func (s *SegmentsService) Update(ctx context.Context, id string, params Params) (Object, error)

Update changes a segment. publication_id travels in the query string and the body alike.

type SendEmailRequest

type SendEmailRequest struct {
	// From is a verified sender, e.g. "Acme <hello@acme.com>".
	From string `json:"from,omitempty"`
	// SenderID selects a saved sender ("snd_…") instead of From.
	SenderID string `json:"sender_id,omitempty"`

	To      []string `json:"to"`
	Subject string   `json:"subject"`

	HTML string `json:"html,omitempty"`
	Text string `json:"text,omitempty"`
	// Template renders a published template server-side. Mutually exclusive
	// with HTML.
	Template *TemplateRef `json:"template,omitempty"`

	CC      []string `json:"cc,omitempty"`
	BCC     []string `json:"bcc,omitempty"`
	ReplyTo []string `json:"reply_to,omitempty"`

	// ScheduledAt queues the send for later, ISO 8601: "2026-09-01T09:00:00Z".
	ScheduledAt string `json:"scheduled_at,omitempty"`

	Tags    []Tag             `json:"tags,omitempty"`
	Headers map[string]string `json:"headers,omitempty"`

	Attachments []Attachment `json:"attachments,omitempty"`

	// TrackingOpen and TrackingClick opt this message out of the open pixel or
	// out of rewritten links. They are pointers because "unset" and "false" are
	// different: unset means tracked, as it always has been. A sending domain
	// with tracking switched off cannot be overridden from here — policy
	// narrows, it never widens.
	TrackingOpen  *bool `json:"tracking_open,omitempty"`
	TrackingClick *bool `json:"tracking_click,omitempty"`

	// Extra carries wire fields this SDK version does not name yet. Its keys
	// are merged over the encoded struct, so a field the API adds tomorrow is
	// sendable today.
	Extra Params `json:"-"`
}

SendEmailRequest is the body of POST /v1/emails.

Set the From with exactly one of From (a "Name <email>" string) or SenderID (a named, verified publication sender, which also supplies its default reply-to). Provide HTML/Text OR Template, never both.

To, CC and BCC are capped at 50 recipients COMBINED — the provider refuses a larger message, so the API rejects it rather than accepting a send that dies downstream where you cannot see it.

func (SendEmailRequest) MarshalJSON

func (r SendEmailRequest) MarshalJSON() ([]byte, error)

MarshalJSON merges Extra over the named fields.

type SendEmailResponse

type SendEmailResponse struct {
	Object string `json:"object"`
	ID     string `json:"id"`
}

SendEmailResponse is what a send returns: the id you look the send up by, and the id webhooks reference.

type SendPostRequest

type SendPostRequest struct {
	ScheduledAt string `json:"scheduled_at,omitempty"`

	// Extra carries wire fields this SDK version does not name yet.
	Extra Params `json:"-"`
}

SendPostRequest is the body of POST /v1/posts/{id}/send. Leave it zero to send now; set ScheduledAt (ISO 8601) to schedule.

func (SendPostRequest) MarshalJSON

func (r SendPostRequest) MarshalJSON() ([]byte, error)

MarshalJSON merges Extra over the named fields.

type SendTestPostRequest

type SendTestPostRequest struct {
	Recipients []string `json:"recipients"`
	From       string   `json:"from,omitempty"`
	ReplyTo    string   `json:"reply_to,omitempty"`

	// Extra carries wire fields this SDK version does not name yet.
	Extra Params `json:"-"`
}

SendTestPostRequest is the body of POST /v1/posts/{id}/test. Up to 10 recipients; From must use a verified domain.

func (SendTestPostRequest) MarshalJSON

func (r SendTestPostRequest) MarshalJSON() ([]byte, error)

MarshalJSON merges Extra over the named fields.

type SendTestPostResponse

type SendTestPostResponse struct {
	SentTo   []string `json:"sent_to"`
	FailedTo []string `json:"failed_to"`
}

SendTestPostResponse reports which test recipients were reached.

type SendersService

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

SendersService is the `senders` resource — named From identities. Reach it as client.Senders.

Senders are scoped to a publication. Create takes name and email (the address must live on a verified, DKIM-verified email domain), plus optional reply_to and is_default. The email is immutable, so Update only changes name, reply_to and is_default.

func (*SendersService) Create

func (s *SendersService) Create(ctx context.Context, params Params) (Object, error)

Create adds a sender.

func (*SendersService) Delete

func (s *SendersService) Delete(ctx context.Context, id string, params Params) (Object, error)

Delete removes a sender. Requires publication_id.

func (*SendersService) Get

func (s *SendersService) Get(ctx context.Context, id string, params Params) (Object, error)

Get retrieves one sender. Requires publication_id.

func (*SendersService) List

func (s *SendersService) List(ctx context.Context, params Params) (*List, error)

List lists senders, cursor-paginated. Filters: publication_id (required), limit, after (a cursor from a previous next_cursor).

func (*SendersService) Update

func (s *SendersService) Update(ctx context.Context, id string, params Params) (Object, error)

Update changes a sender's name, reply_to or is_default. publication_id is required in the body — unlike most updates, this one reads nothing from the query string.

type SuppressionsService

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

SuppressionsService is the `suppressions` resource — the team-wide do-not-send list. Reach it as client.Suppressions.

Suppressions are team-scoped: there is no publication_id here.

func (*SuppressionsService) Add

func (s *SuppressionsService) Add(ctx context.Context, params Params) (Object, error)

Add adds addresses to the suppression list. Takes emails (up to 1000) and an optional reason. Returns {"added": n}.

func (*SuppressionsService) Export

func (s *SuppressionsService) Export(ctx context.Context) (string, error)

Export returns the whole suppression list as CSV — the raw text/csv body (email,reason,source,created_at with a header row), not JSON.

func (*SuppressionsService) List

func (s *SuppressionsService) List(ctx context.Context, params Params) (*List, error)

List lists suppression entries, cursor-paginated. Optional filters: reason, q (email search), created_after, created_before, limit, starting_after (a cursor from a previous next_cursor).

func (*SuppressionsService) Remove

func (s *SuppressionsService) Remove(ctx context.Context, params Params) (Object, error)

Remove takes addresses off the suppression list. Takes emails. Returns {"removed": n}. The body travels on a DELETE, which is what this endpoint reads.

type Tag

type Tag struct {
	Name  string `json:"name"`
	Value string `json:"value"`
}

Tag is a key/value label carried with a send, for filtering and analytics later.

type TemplateRef

type TemplateRef struct {
	ID        string                 `json:"id"`
	Variables map[string]interface{} `json:"variables,omitempty"`
}

TemplateRef seeds a send from a published server-side template instead of inline HTML. Variables fill the template's placeholders.

type TemplatesService

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

TemplatesService is the `templates` resource — reusable server-side email templates. Reach it as client.Templates.

Templates are scoped to a publication (except Render, which just renders a spec). Create one from raw html, a json-render spec, or an editor_doc (a Studio editor design), then Publish it before seeding posts or emails from it.

func (*TemplatesService) Create

func (s *TemplatesService) Create(ctx context.Context, params Params) (Object, error)

Create adds a template from html, a spec, OR an editor_doc — exactly one is required, and the server renders html from an editor_doc, so do not send both. Takes publication_id and name, plus optional style_profile, mailtea_theme, global_css, category, preview_image_url, tags, description, text, subject, from, reply_to and variables.

func (*TemplatesService) Delete

func (s *TemplatesService) Delete(ctx context.Context, id string, params Params) (Object, error)

Delete removes a template. Requires publication_id.

func (*TemplatesService) Duplicate

func (s *TemplatesService) Duplicate(ctx context.Context, id string, params Params) (Object, error)

Duplicate copies a template into a new draft. Requires publication_id.

func (*TemplatesService) Get

func (s *TemplatesService) Get(ctx context.Context, id string, params Params) (Object, error)

Get retrieves one template. Requires publication_id.

func (*TemplatesService) List

func (s *TemplatesService) List(ctx context.Context, params Params) (*List, error)

List lists templates, cursor-paginated. Filters: publication_id (required), limit, after (a cursor from a previous next_cursor).

func (*TemplatesService) Publish

func (s *TemplatesService) Publish(ctx context.Context, id string, params Params) (Object, error)

Publish makes a template available to seed posts and emails. Requires publication_id.

func (*TemplatesService) Render

func (s *TemplatesService) Render(ctx context.Context, params Params) (Object, error)

Render renders a json-render `spec` (with optional `variables`) to HTML without creating a template. Returns {"html": ..., "text": ...}.

func (*TemplatesService) RestoreVersion

func (s *TemplatesService) RestoreVersion(ctx context.Context, id string, version interface{}, params Params) (Object, error)

RestoreVersion puts an older design from Versions back onto the template. Requires publication_id.

Restoring is a content write, so THE TEMPLATE RETURNS TO DRAFT — automations and the API stop sending it until Publish is called again. The reply's `unpublished` reports whether that just happened; re-publishing is the caller's job.

History is forward-only: the design being replaced is recorded as its own version first, then the restored design is appended as the new newest one. Nothing is rewound or deleted, so a restore is itself undone by restoring the entry directly above it.

Restoring the design that is already current writes nothing and returns restored: false with reason: "identical" and unpublished: false, so a no-op restore cannot unpublish a live template. A version that has aged out of retention returns a *Error with Code "template_version_not_found".

version is an int or a string — whatever Versions reported.

func (*TemplatesService) Unpublish

func (s *TemplatesService) Unpublish(ctx context.Context, id string, params Params) (Object, error)

Unpublish returns a published template to draft. published_at is kept — it records that the template was published once, not that it still is. Requires publication_id.

func (*TemplatesService) Update

func (s *TemplatesService) Update(ctx context.Context, id string, params Params) (Object, error)

Update changes a template. An editor_doc re-renders html server-side, so do not send both. global_css, category, preview_image_url, tags, text, subject, from and reply_to accept an explicit nil to clear them. publication_id is required and travels in the query string as well as the body.

func (*TemplatesService) Versions

func (s *TemplatesService) Versions(ctx context.Context, id string, params Params) (Object, error)

Versions lists a template's design history, newest first. Requires publication_id; optional limit (the server caps it at the retained maximum).

Entries are metadata only — version, origin ("edit", "publish" or "restore"), restored_from_version, format, name, sealed, is_current, created_at, updated_at and author — never the design document, which one entry alone can carry half a megabyte of. is_current marks the design the template is serving right now, which is not always the newest entry: a metadata-only update touches the template without recording a version.

The reply also carries `retention`: only the newest max_versions are kept, and consecutive edits by the same author within coalesce_window_seconds collapse into one entry.

type TopicsService

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

TopicsService is the `topics` resource — topic definitions. Reach it as client.Topics.

Topics are scoped to a publication. This manages topic definitions only; assigning topics to contacts is not yet exposed by the API.

func (*TopicsService) Create

func (s *TopicsService) Create(ctx context.Context, request CreateTopicRequest) (Object, error)

Create adds a topic definition.

func (*TopicsService) Delete

func (s *TopicsService) Delete(ctx context.Context, id string, params Params) (Object, error)

Delete removes a topic. Requires publication_id.

func (*TopicsService) Get

func (s *TopicsService) Get(ctx context.Context, id string, params Params) (Object, error)

Get retrieves one topic. Requires publication_id.

func (*TopicsService) List

func (s *TopicsService) List(ctx context.Context, params Params) (*List, error)

List lists topics. Requires publication_id.

func (*TopicsService) Update

func (s *TopicsService) Update(ctx context.Context, id string, params Params) (Object, error)

Update changes a topic. publication_id travels in the query string and the body alike.

type TrackingDomainsService

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

TrackingDomainsService covers tracking sub-domains (CNAME) under a domain — used to serve open-pixel and click-tracking links from your own domain. Reach it as client.Domains.Tracking.

func (*TrackingDomainsService) Create

func (s *TrackingDomainsService) Create(ctx context.Context, domainID string, params Params) (Object, error)

Create adds a tracking sub-domain. Takes publication_id and subdomain. The response's `records` lists the CNAME to add.

publication_id goes in the query string and only `subdomain` in the body, which is what this endpoint reads.

func (*TrackingDomainsService) Delete

func (s *TrackingDomainsService) Delete(ctx context.Context, domainID, trackingDomainID string, params Params) (Object, error)

Delete removes a tracking sub-domain. Requires publication_id.

func (*TrackingDomainsService) List

func (s *TrackingDomainsService) List(ctx context.Context, domainID string, params Params) (Object, error)

List lists a domain's tracking sub-domains. Requires publication_id.

func (*TrackingDomainsService) Verify

func (s *TrackingDomainsService) Verify(ctx context.Context, domainID, trackingDomainID string, params Params) (Object, error)

Verify checks a tracking sub-domain's CNAME. Requires publication_id.

type UpdateContactRequest

type UpdateContactRequest struct {
	PublicationID string `json:"publication_id"`
	Status        string `json:"status,omitempty"`

	// Extra carries wire fields this SDK version does not name yet.
	Extra Params `json:"-"`
}

UpdateContactRequest is the body of PATCH /v1/contacts/{id_or_email}. PublicationID is required — it goes in the query string and the body alike.

func (UpdateContactRequest) MarshalJSON

func (r UpdateContactRequest) MarshalJSON() ([]byte, error)

MarshalJSON merges Extra over the named fields.

type UpdateEmailRequest

type UpdateEmailRequest struct {
	ScheduledAt string `json:"scheduled_at,omitempty"`

	// Extra carries wire fields this SDK version does not name yet.
	Extra Params `json:"-"`
}

UpdateEmailRequest reschedules a scheduled email. ScheduledAt is currently the only field the API accepts.

func (UpdateEmailRequest) MarshalJSON

func (r UpdateEmailRequest) MarshalJSON() ([]byte, error)

MarshalJSON merges Extra over the named fields.

type WebhooksService

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

WebhooksService is the `webhooks` resource — outbound event subscriptions. Reach it as client.Webhooks.

Scoped to a publication. Create returns the signing_secret ONCE; store it and verify deliveries with VerifyWebhookSignature.

func (*WebhooksService) Create

func (s *WebhooksService) Create(ctx context.Context, params Params) (Object, error)

Create registers a webhook endpoint.

func (*WebhooksService) Delete

func (s *WebhooksService) Delete(ctx context.Context, id string, params Params) (Object, error)

Delete removes a webhook endpoint. Requires publication_id.

func (*WebhooksService) Get

func (s *WebhooksService) Get(ctx context.Context, id string, params Params) (Object, error)

Get retrieves one webhook endpoint. Requires publication_id.

func (*WebhooksService) List

func (s *WebhooksService) List(ctx context.Context, params Params) (*List, error)

List lists webhook endpoints. Requires publication_id.

func (*WebhooksService) Update

func (s *WebhooksService) Update(ctx context.Context, id string, params Params) (Object, error)

Update changes a webhook endpoint. publication_id travels in the query string and the body alike.

Jump to

Keyboard shortcuts

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