unsent
unsent.dev
Get Started

Go

Official Unsent Go SDK for sending emails and managing contacts.

This guide shows how to install and use the official unsent Go SDK.

Installation

Install the SDK using go get to add it to your project's dependencies:

go get github.com/souravsspace/unsent-go

Initialize

To start using the SDK, you need to create a client instance. You'll need your API key, which you can find in your Unsent dashboard.

Import the package and create a new client using unsent.NewClient. You can pass the API key directly, or if you have the UNSENT_API_KEY environment variable set, you can pass an empty string.

package main

import (
    "log"
    "github.com/souravsspace/unsent-go"
)

func main() {
    // Initialize with API key
    client, err := unsent.NewClient("un_xxx")
    
    // Or use environment variable UNSENT_API_KEY
    // client, err := unsent.NewClient("")
    
    if err != nil {
        log.Fatal(err)
    }
}

Send an email

Now you're ready to send your first email. You can do this by creating an unsent.EmailCreate struct and passing it to the client.Emails.Send method.

Here is a simple example of sending an HTML email:

package main

import (
    "fmt"
    "log"
    "github.com/souravsspace/unsent-go"
)

func main() {
    // Initialize the client
    client, err := unsent.NewClient("un_xxx")
    if err != nil {
        log.Fatal(err)
    }

    // Send the email
    email, err := client.Emails.Send(unsent.EmailCreate{
        To:      "user@example.com",
        From:    "no-reply@yourdomain.com",
        Subject: "Welcome",
        HTML:    "<strong>Hello!</strong>",
    })

    if err != nil {
        log.Printf("Error: %v", err)
    } else {
        fmt.Printf("Email sent! ID: %s\n", email.ID)
    }
}

With attachments and scheduling

You can also send emails with attachments and schedule them for a later time.

  • Attachments: Create a slice of unsent.Attachment structs. The content must be a Base64 encoded string.
  • Scheduling: Set the ScheduledAt field with a pointer to a time.Time object.
import "time"

// Schedule for 10 minutes from now
scheduledTime := time.Now().Add(10 * time.Minute)

email, err := client.Emails.Create(unsent.EmailCreate{
    To:      "user@example.com",
    From:    "no-reply@yourdomain.com",
    Subject: "Report",
    Text:    "See attached.",
    Attachments: []unsent.Attachment{
        {
            Filename: "report.txt",
            Content:  "SGVsbG8gd29ybGQ=", // Content must be Base64 encoded
        },
    },
    ScheduledAt: &scheduledTime,
})

Batch send

If you need to send multiple emails at once, use the client.Emails.Batch method. This accepts a slice of unsent.EmailBatchItem.

emails := []unsent.EmailBatchItem{
    {
        To:      "a@example.com",
        From:    "no-reply@yourdomain.com",
        Subject: "A",
        HTML:    "<p>A</p>",
    },
    {
        To:      "b@example.com",
        From:    "no-reply@yourdomain.com",
        Subject: "B",
        HTML:    "<p>B</p>",
    },
}

response, err := client.Emails.Batch(emails)
if err != nil {
    log.Printf("Error: %v", err)
} else {
    fmt.Printf("Sent %d emails\n", len(response.Emails))
}

Idempotent Retries

To safely retry requests, you can use unsent.WithIdempotencyKey.

// For single email
client.Emails.Send(email, unsent.WithIdempotencyKey("unique-key-123"))

// For batch emails
client.Emails.Batch(emails, unsent.WithIdempotencyKey("batch-unique-key-123"))

Retrieve and manage emails

You can retrieve the status of sent emails, update their scheduled time, or cancel them if they haven't been sent yet.

Get an email

To check the status of a specific email, use client.Emails.Get with the email ID:

email, err := client.Emails.Get("email_123")
if err != nil {
    log.Printf("Error: %v", err)
} else {
    fmt.Printf("Email status: %s\n", email.Status)
}

Update schedule time

If you need to change when a scheduled email will be sent, you can update its ScheduledAt property using client.Emails.Update:

import "time"

newTime := time.Now().Add(1 * time.Hour)

response, err := client.Emails.Update("email_123", unsent.EmailUpdate{
    ScheduledAt: &newTime,
})

Cancel a scheduled email

To stop a scheduled email from being sent, use the client.Emails.Cancel method:

response, err := client.Emails.Cancel("email_123")
if err != nil {
    log.Printf("Error: %v", err)
} else {
    fmt.Println("Email cancelled successfully")
}

Contacts

Manage your audience by creating and updating contacts. Contacts can be organized into "contact books" (identified by book_id).

Create a contact

Add a new contact to a specific contact book. You can include metadata like their subscription plan.

contact, err := client.Contacts.Create("book_123", unsent.ContactCreate{
    Email:     "user@example.com",
    FirstName: "Jane",
    Metadata: map[string]interface{}{
        "plan": "pro",
    },
})

Get a contact

Retrieve details about a specific contact using their ID and the book ID:

contact, err := client.Contacts.Get("book_123", "contact_456")

Update a contact

Update a contact's information, such as their name or metadata:

response, err := client.Contacts.Update("book_123", "contact_456", unsent.ContactUpdate{
    FirstName: "John",
    Metadata: map[string]interface{}{
        "plan": "enterprise",
    },
})

Upsert a contact

Use Upsert to create a contact if they don't exist, or update them if they do. This is useful for syncing data.

contact, err := client.Contacts.Upsert("book_123", "contact_456", unsent.ContactUpsert{
    Email:     "user@example.com",
    FirstName: "Jane",
    Metadata: map[string]interface{}{
        "plan": "pro",
    },
})

Delete a contact

Remove a contact from a book:

response, err := client.Contacts.Delete("book_123", "contact_456")

Campaigns

Campaigns allow you to send emails to an entire contact book.

Create a campaign

Create a new campaign by specifying the content and the target contact book ID.

campaign, err := client.Campaigns.Create(unsent.CampaignCreate{
    Name:          "Welcome Series",
    Subject:       "Welcome!",
    HTML:          "<p>Thanks for joining us!</p>",
    From:          "welcome@yourdomain.com",
    ContactBookID: "book_123",
})

Schedule a campaign

Once created, you can schedule the campaign to be sent at a specific time.

response, err := client.Campaigns.Schedule(campaign.ID, unsent.CampaignSchedule{
    ScheduledAt: "2024-12-01T10:00:00Z",
})

Pause and resume campaigns

You can pause a running or scheduled campaign and resume it later.

// Pause
pauseResp, err := client.Campaigns.Pause("campaign_123")

// Resume
resumeResp, err := client.Campaigns.Resume("campaign_123")

Domains

Manage the domains you use to send emails.

List domains

Retrieve a list of all your domains and their verification status.

domains, err := client.Domains.List()
if err != nil {
    log.Printf("Error: %v", err)
} else {
    for _, domain := range domains {
        fmt.Printf("Domain: %s, Status: %s\n", domain.Domain, domain.Status)
    }
}

Create a domain

Add a new domain to your account.

domain, err := client.Domains.Create(unsent.DomainCreate{
    Domain: "yourdomain.com",
})

Verify a domain

Check the verification status of a domain.

response, err := client.Domains.Verify(123)

Error handling

The SDK supports different ways of handling errors.

Standard Error Handling (Default)

By default, the SDK methods return an error if the API request fails or returns a non-2xx status code. You can check for specific API errors by casting the error to *unsent.APIError.

import "github.com/souravsspace/unsent-go"

client, err := unsent.NewClient("un_xxx")
if err != nil {
    log.Fatal(err)
}

email, err := client.Emails.Get("email_123")
if err != nil {
    // Check if it's an API error
    if apiErr, ok := err.(*unsent.APIError); ok {
        fmt.Printf("API Error: %s - %s\n", apiErr.Code, apiErr.Message)
    } else {
        // Handle other errors (network, etc.)
        log.Printf("Error: %v", err)
    }
}

Disable Automatic Error Raising

If you prefer to handle HTTP errors manually without the SDK treating non-2xx responses as errors, you can use unsent.WithRaiseOnError(false).

client, err := unsent.NewClient("un_xxx", unsent.WithRaiseOnError(false))

Advanced Configuration

For advanced use cases, such as adding custom timeouts, proxies, or changing the base URL, you can provide options to NewClient.

Custom HTTP Client

import (
    "net/http"
    "time"
)

// Create a custom HTTP client with a timeout
httpClient := &http.Client{
    Timeout: 30 * time.Second,
}

// Initialize the SDK with the custom client
client, err := unsent.NewClient("un_xxx", unsent.WithHTTPClient(httpClient))

Custom Base URL

If you need to point the SDK to a different URL (e.g. for testing), you can use WithBaseURL.

client, err := unsent.NewClient("un_xxx", unsent.WithBaseURL("https://api.example.com"))