Skip to main content

1. Installation

Install the SDK using Go modules:
go get github.com/lettermint/lettermint-go
Requires Go 1.21 or higher.

2. Send your first email

Initialize the client with your API token:
package main

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

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

func main() {
    client, err := lettermint.New(os.Getenv("LETTERMINT_API_TOKEN"))
    if err != nil {
        log.Fatal(err)
    }
}
Send your first email:
ctx := context.Background()

resp, err := client.Email(ctx).
    From("John Doe <john@yourdomain.com>").
    To("recipient@example.com").
    Subject("Hello from Lettermint").
    Text("This is a test email sent using the Lettermint Go SDK.").
    Send()

if err != nil {
    log.Fatal(err)
}

fmt.Printf("Email sent with ID: %s\n", resp.MessageID)

3. Email Features

Basic Email

Send a simple text or HTML email:
resp, err := client.Email(ctx).
    From("John Doe <john@yourdomain.com>").
    To("recipient@example.com").
    Subject("Your account is ready!").
    HTML("<h1>Welcome!</h1><p>Thanks for signing up.</p>").
    Text("Welcome! Thanks for signing up.").
    Send()

Multiple Recipients

Send to multiple recipients using CC and BCC:
resp, err := client.Email(ctx).
    From("John Doe <john@yourdomain.com>").
    To("user1@example.com", "user2@example.com").
    CC("manager@yourdomain.com").
    BCC("archive@yourdomain.com").
    Subject("Monthly Newsletter").
    HTML("<h1>This Month's Updates</h1>").
    Send()

Custom Headers and Reply-To

Add custom headers and set reply-to addresses:
resp, err := client.Email(ctx).
    From("support@yourdomain.com").
    To("customer@example.com").
    ReplyTo("help@yourdomain.com").
    Subject("Support Ticket #12345").
    Headers(map[string]string{
        "X-Priority":  "1",
        "X-Ticket-ID": "12345",
    }).
    HTML("<p>Your support ticket has been updated.</p>").
    Send()

Metadata

Add metadata for tracking and webhook payloads:
resp, err := client.Email(ctx).
    From("notifications@yourdomain.com").
    To("user@example.com").
    Subject("Order Confirmation").
    Metadata(map[string]string{
        "order_id":    "12345",
        "customer_id": "cust_789",
        "campaign":    "order_confirmation",
    }).
    HTML("<p>Your order has been confirmed.</p>").
    Send()
Metadata is included in webhook payloads but not added to the actual email headers. Use it for tracking and analytics purposes.

Tags

Categorize emails for filtering and analytics:
resp, err := client.Email(ctx).
    From("alerts@yourdomain.com").
    To("admin@example.com").
    Subject("System Alert").
    Tag("system-alerts").
    HTML("<p>Critical system alert detected.</p>").
    Send()
One tag per message. Tags can contain letters, numbers, hyphens, underscores, and spaces (max 255 characters). See Tags documentation for more details.

Route Selection

Direct emails to specific routes within your project:
resp, err := client.Email(ctx).
    From("notifications@yourdomain.com").
    To("user@example.com").
    Subject("Welcome!").
    Route("transactional").
    HTML("<p>Welcome to our platform.</p>").
    Send()

File Attachments

Attach files to your emails:
import (
    "encoding/base64"
    "os"
)

// Read and encode file
fileContent, err := os.ReadFile("/path/to/document.pdf")
if err != nil {
    log.Fatal(err)
}
encodedContent := base64.StdEncoding.EncodeToString(fileContent)

resp, err := client.Email(ctx).
    From("invoices@yourdomain.com").
    To("customer@example.com").
    Subject("Your Invoice").
    HTML("<p>Please find your invoice attached.</p>").
    Attach("invoice.pdf", encodedContent).
    Send()

Inline Images

Embed images directly in your HTML using Content-ID:
logoContent, _ := os.ReadFile("/path/to/logo.png")
encodedLogo := base64.StdEncoding.EncodeToString(logoContent)

resp, err := client.Email(ctx).
    From("marketing@yourdomain.com").
    To("customer@example.com").
    Subject("Welcome to Our Platform").
    HTML(`<p>Welcome!</p><img src="cid:logo" alt="Company Logo">`).
    AttachWithContentID("logo.png", encodedLogo, "logo").
    Send()

Idempotency

Prevent duplicate emails with idempotency keys:
resp, err := client.Email(ctx).
    From("notifications@yourdomain.com").
    To("user@example.com").
    Subject("Order Confirmation").
    HTML("<p>Your order has been confirmed.</p>").
    IdempotencyKey("order-12345-confirmation").
    Send()
Use a unique key per logical email (e.g., combining order ID + email type). Retrying with the same key won’t send duplicate emails.

4. Client Configuration

Customize the client with functional options:
import "time"

client, err := lettermint.New(
    os.Getenv("LETTERMINT_API_TOKEN"),
    lettermint.WithTimeout(30*time.Second),
    lettermint.WithBaseURL("https://api.lettermint.co/v1"),
)

5. Response

resp, err := client.Email(ctx).
    From("John Doe <john@yourdomain.com>").
    To("recipient@example.com").
    Subject("Test").
    Text("Hello!").
    Send()

if err != nil {
    log.Fatal(err)
}

fmt.Println(resp.MessageID) // Unique email ID
fmt.Println(resp.Status)    // Current status

6. Error Handling

Handle errors with type checking:
import "errors"

resp, err := client.Email(ctx).
    From("sender@yourdomain.com").
    To("recipient@example.com").
    Subject("Test").
    Text("Hello!").
    Send()

if err != nil {
    var apiErr *lettermint.APIError
    if errors.As(err, &apiErr) {
        fmt.Printf("API Error (%d): %s\n", apiErr.StatusCode, apiErr.Message)
        fmt.Printf("Validation errors: %v\n", apiErr.Errors)
        return
    }

    // Check specific error types
    switch {
    case errors.Is(err, lettermint.ErrUnauthorized):
        fmt.Println("Invalid API token")
    case errors.Is(err, lettermint.ErrValidation):
        fmt.Println("Invalid request parameters")
    case errors.Is(err, lettermint.ErrRateLimited):
        fmt.Println("Rate limit exceeded")
    case errors.Is(err, lettermint.ErrTimeout):
        fmt.Println("Request timed out")
    default:
        fmt.Printf("Unexpected error: %v\n", err)
    }
}

7. Webhook Verification

Verify incoming webhooks from Lettermint:
import "net/http"

func webhookHandler(w http.ResponseWriter, r *http.Request) {
    event, err := lettermint.VerifyWebhookFromRequest(
        r,
        os.Getenv("LETTERMINT_WEBHOOK_SECRET"),
        lettermint.DefaultWebhookTolerance,
    )
    if err != nil {
        http.Error(w, "Invalid signature", http.StatusUnauthorized)
        return
    }

    switch event.Event {
    case "message.delivered":
        log.Printf("Email delivered to %s", event.Data.Recipient)
    case "message.hard_bounced":
        log.Printf("Hard bounce for %s", event.Data.Recipient)
    case "message.soft_bounced":
        log.Printf("Soft bounce for %s", event.Data.Recipient)
    }

    w.WriteHeader(http.StatusOK)
}
Store your webhook secret in an environment variable. Never hardcode secrets in your application.

Next Steps

Tags

Organize and filter emails with tags.

Tracking

Track opens, clicks, and deliverability.

Webhooks

Receive real-time delivery notifications.

SMTP Alternative

Send via SMTP instead of the API.

GitHub Repository

Find the complete source code, report issues, or contribute on GitHub.