Go SDK
The official Go SDK for Posthawk. Zero external dependencies — built entirely on Go's standard library.
InstallationAdd posthawk-go to your Go module:
Example
go get github.com/endibuka/posthawk-goQuick StartCreate a client and send your first email:
Example
package main
import (
"context"
"fmt"
"log"
posthawk "github.com/endibuka/posthawk-go"
)
func main() {
client := posthawk.New("ck_live_...")
result, err := client.Emails.Send(context.Background(), &posthawk.SendEmailRequest{
From: "hi@yourdomain.com",
To: []string{"user@example.com"},
Subject: "Hello from Posthawk",
HTML: "<h1>Welcome!</h1><p>Your account is ready.</p>",
})
if err != nil {
log.Fatal(err)
}
fmt.Println("Sent! Job ID:", result.JobID)
}Send EmailThe SendEmailRequest struct supports all email fields: | Field | Type | Required | Description | |---|---|---|---| | From | string | Yes | Sender email address | | To | []string | Yes | Recipient email addresses | | Subject | string | Yes | Email subject line | | HTML | string | No | HTML body | | Text | string | No | Plain text body | | Cc | []string | No | CC recipients | | Bcc | []string | No | BCC recipients | | ReplyTo | string | No | Reply-to address | | TemplateID | string | No | Template identifier | | Variables | map[string]string | No | Template variables | | Headers | map[string]string | No | Custom email headers | | ScheduledFor | string | No | RFC 3339 send time | | Timezone | string | No | IANA timezone | | Metadata | map[string]any | No | Custom metadata | | Tags | map[string]any | No | Email tags |
Example
result, err := client.Emails.Send(ctx, &posthawk.SendEmailRequest{
From: "hi@yourdomain.com",
To: []string{"alice@example.com", "bob@example.com"},
Cc: []string{"manager@example.com"},
Subject: "Weekly Report",
HTML: "<h1>Report</h1>",
Text: "Plain text fallback",
Headers: map[string]string{"X-Custom": "value"},
Metadata: map[string]any{"campaign": "onboarding"},
Tags: map[string]any{"type": "transactional"},
})Check Delivery StatusPoll the status of a sent email by job ID. Status values: pending, processing, completed, failed.
Example
status, err := client.Emails.Get(ctx, "job-id-here")
if err != nil {
log.Fatal(err)
}
fmt.Println("Status:", status.Status) // pending | processing | completed | failed
fmt.Println("Created:", status.CreatedAt)List Scheduled EmailsRetrieve scheduled emails with optional filters:
Example
limit := 10
list, err := client.Scheduled.List(ctx, &posthawk.ListScheduledParams{
Status: "scheduled",
Limit: &limit,
})
if err != nil {
log.Fatal(err)
}
for _, email := range list.Data {
fmt.Printf("%s → %s\n", email.Subject, email.ScheduledFor)
}
fmt.Println("Total:", list.Total)Get Scheduled EmailRetrieve a single scheduled email by ID:
Example
result, err := client.Scheduled.Get(ctx, "scheduled-email-id")
if err != nil {
log.Fatal(err)
}
fmt.Println("Subject:", result.Data.Subject)
fmt.Println("Scheduled for:", result.Data.ScheduledFor)
fmt.Println("Status:", result.Data.Status)Cancel Scheduled EmailCancel a scheduled email before it sends:
Example
result, err := client.Scheduled.Cancel(ctx, "scheduled-email-id")
if err != nil {
log.Fatal(err)
}
fmt.Println(result.Message) // "Scheduled email cancelled"Reschedule EmailChange the send time of a scheduled email:
Example
result, err := client.Scheduled.Reschedule(ctx, "scheduled-email-id", &posthawk.RescheduleRequest{
ScheduledFor: "2026-04-01T10:00:00Z",
})
if err != nil {
log.Fatal(err)
}
fmt.Println("New time:", result.Data.ScheduledFor)Error HandlingAll methods return Go's standard (T, error) tuples. Errors are of type *posthawk.Error with StatusCode and Message fields. Use errors.As for type assertion:
Example
result, err := client.Emails.Send(ctx, &posthawk.SendEmailRequest{
From: "hi@yourdomain.com",
To: []string{"user@example.com"},
Subject: "Test",
HTML: "<p>Hello</p>",
})
if err != nil {
var posthawkErr *posthawk.Error
if errors.As(err, &posthawkErr) {
fmt.Printf("API error %d: %s\n", posthawkErr.StatusCode, posthawkErr.Message)
} else {
fmt.Printf("Unexpected error: %v\n", err)
}
return
}
fmt.Println("Success:", result.JobID)Domain ManagementManage sending domains programmatically — add, verify, enable inbound receiving, configure webhooks, and set sending limits:
Example
// Add a domain
domain, err := client.Domains.Create(ctx, &posthawk.CreateDomainRequest{
Domain: "mail.customer.com",
Region: "us-east-1",
})
// domain.Data.DnsRecords → DNS records to configure
// List all domains
domains, err := client.Domains.List(ctx)
// Trigger verification check
status, err := client.Domains.Verify(ctx, "domain-uuid")
// status.Data.SendingEnabled → true when verified
// Enable inbound receiving
client.Domains.EnableReceiving(ctx, "domain-uuid")
// Set a webhook for inbound emails
client.Domains.UpdateWebhook(ctx, "domain-uuid", &posthawk.UpdateDomainWebhookRequest{
WebhookURL: strPtr("https://yourapp.com/api/incoming-email"),
})
// Test the webhook
client.Domains.TestWebhook(ctx, "domain-uuid")
// Set per-domain sending limits
client.Domains.UpdateLimits(ctx, "domain-uuid", &posthawk.UpdateDomainLimitsRequest{
MaxDailyEmails: intPtr(1000),
MaxMonthlyEmails: intPtr(25000),
})
// Remove limits (nil = unlimited)
client.Domains.UpdateLimits(ctx, "domain-uuid", &posthawk.UpdateDomainLimitsRequest{
MaxDailyEmails: nil,
MaxMonthlyEmails: nil,
})
// Delete a domain
client.Domains.Delete(ctx, "domain-uuid")Self-Hosted ConfigurationPoint the SDK at your own Posthawk instance using WithBaseURL. You can also provide a custom http.Client:
Example
// Custom base URL for self-hosted
client := posthawk.New("ck_live_...",
posthawk.WithBaseURL("https://api.yourdomain.com"),
)
// Custom HTTP client with timeout
client := posthawk.New("ck_live_...",
posthawk.WithHTTPClient(&http.Client{
Timeout: 10 * time.Second,
}),
)