# Go

## 1. Installation

Install the SDK using Go modules:

```bash
go get github.com/lettermint/lettermint-go
```

:::note
Requires Go 1.21 or higher.
:::

## 2. Send your first email

Initialize the client with your API token:

```go
package main

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

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

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

Send your first email:

```go
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:

```go
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:

```go
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:

```go
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:

```go
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()
```

:::note
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:

```go
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()
```

:::note
One tag per message. Tags can contain letters, numbers, hyphens, underscores, and spaces (max 255 characters).
See [Tags documentation](/platform/emails/tags) for more details.
:::

### Route Selection

Direct emails to specific routes within your project:

```go
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:

```go
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:

```go
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:

```go
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()
```

:::tip
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:

```go
import "time"

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

## 5. Response

```go
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:

```go
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:

```go
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)
}
```

:::warning
Store your webhook secret in an environment variable. Never hardcode secrets in your application.
:::

## Next Steps

<CardGroup cols={2}>
    <Card title="Tags" icon="tag" href="/platform/emails/tags">
        Organize and filter emails with tags.
    </Card>
    <Card title="Tracking" icon="chart-line" href="/platform/emails/tracking/introduction">
        Track opens, clicks, and deliverability.
    </Card>
    <Card title="Webhooks" icon="webhook" href="/platform/webhooks/introduction">
        Receive real-time delivery notifications.
    </Card>
    <Card title="SMTP Alternative" icon="envelope" href="/guides/send-email-with-smtp">
        Send via SMTP instead of the API.
    </Card>
</CardGroup>

<Card title="GitHub Repository" icon="github" href="https://github.com/lettermint/lettermint-go">
    Find the complete source code, report issues, or contribute on GitHub.
</Card>
