Skip to main content
Get up and running with the Resend Go SDK in minutes. This guide walks you through sending your first email.

Prerequisites

Before you begin, make sure you have:

Send your first email

1

Get your API key

Sign in to your Resend account and navigate to the API Keys page. Create a new API key or copy an existing one.
Keep your API key secure and never commit it to version control. Use environment variables to store sensitive credentials.
Store your API key in an environment variable:
export RESEND_API_KEY="re_your_api_key_here"
2

Create a new Go file

Create a new file called main.go with the following code:
package main

import (
    "context"
    "fmt"
    "os"

    "github.com/resend/resend-go/v3"
)

func main() {
    ctx := context.TODO()
    apiKey := os.Getenv("RESEND_API_KEY")

    client := resend.NewClient(apiKey)

    params := &resend.SendEmailRequest{
        To:      []string{"[email protected]"},
        From:    "[email protected]",
        Text:    "hello world",
        Subject: "Hello from Golang",
        Cc:      []string{"[email protected]"},
        Bcc:     []string{"[email protected]"},
        ReplyTo: "[email protected]",
    }

    sent, err := client.Emails.SendWithContext(ctx, params)
    if err != nil {
        panic(err)
    }
    fmt.Printf("Sent basic email: %s\n", sent.Id)
}
The example uses [email protected] as the recipient, which is a test email that Resend provides. Replace it with your actual recipient email address.
3

Run your code

Execute your program:
go run main.go
You should see output similar to:
Sent basic email: 4ef2ecd5-9de0-4b8f-a4e5-1c062f3e7a6c
The returned ID is your email’s unique identifier that you can use to track delivery status.
4

Verify email delivery

Check the recipient’s inbox to confirm the email was delivered. You can also view the email in your Resend Dashboard.

Send HTML emails

Enhance your emails with HTML content:
params := &resend.SendEmailRequest{
    To:      []string{"[email protected]"},
    From:    "[email protected]",
    Html:    "<strong>hello world</strong>",
    Subject: "Hello from Golang",
}

sent, err := client.Emails.Send(params)
if err != nil {
    panic(err)
}
fmt.Println(sent.Id)
You can specify both Html and Text fields. The Text field serves as a fallback for email clients that don’t support HTML.

Use idempotency keys

Prevent duplicate emails by using idempotency keys. This is useful when you want to ensure an email is only sent once, even if your code retries the request:
ctx := context.TODO()

params := &resend.SendEmailRequest{
    To:      []string{"[email protected]"},
    From:    "[email protected]",
    Text:    "hello world",
    Subject: "Hello from Golang",
}

options := &resend.SendEmailOptions{
    IdempotencyKey: "unique-idempotency-key",
}

sent, err := client.Emails.SendWithOptions(ctx, params, options)
if err != nil {
    panic(err)
}
fmt.Printf("Sent email with idempotency key: %s\n", sent.Id)
If you send the same request with the same idempotency key, Resend will return the original email ID instead of sending a duplicate.

Send with attachments

Attach files to your emails using either local file content or remote URLs:
import (
    "os"
    "github.com/resend/resend-go/v3"
)

func main() {
    ctx := context.TODO()
    apiKey := os.Getenv("RESEND_API_KEY")
    client := resend.NewClient(apiKey)

    // Read local file
    fileContent, err := os.ReadFile("invoice.pdf")
    if err != nil {
        panic(err)
    }

    // Create attachments
    localAttachment := &resend.Attachment{
        Content:     fileContent,
        Filename:    "invoice.pdf",
        ContentType: "application/pdf",
    }

    remoteAttachment := &resend.Attachment{
        Path:        "https://example.com/document.pdf",
        Filename:    "document.pdf",
        ContentType: "application/pdf",
    }

    params := &resend.SendEmailRequest{
        To:          []string{"[email protected]"},
        From:        "[email protected]",
        Subject:     "Invoice attached",
        Html:        "<p>Please find your invoice attached.</p>",
        Attachments: []*resend.Attachment{localAttachment, remoteAttachment},
    }

    sent, err := client.Emails.SendWithContext(ctx, params)
    if err != nil {
        panic(err)
    }
    fmt.Println("Sent email with attachments:", sent.Id)
}

Send batch emails

Send multiple emails in a single API call for better performance:
ctx := context.TODO()
apiKey := os.Getenv("RESEND_API_KEY")
client := resend.NewClient(apiKey)

batchEmails := []*resend.SendEmailRequest{
    {
        To:      []string{"[email protected]"},
        From:    "[email protected]",
        Text:    "Welcome to our service!",
        Subject: "Welcome",
    },
    {
        To:      []string{"[email protected]"},
        From:    "[email protected]",
        Text:    "Your order has shipped!",
        Subject: "Order Update",
    },
}

sent, err := client.Batch.SendWithContext(ctx, batchEmails)
if err != nil {
    panic(err)
}

fmt.Printf("Sent %d emails\n", len(sent.Data))
for _, email := range sent.Data {
    fmt.Printf("  - %s\n", email.Id)
}
Batch sending supports both strict validation (default) where all emails must be valid, or permissive mode where valid emails are sent even if some fail validation.

Common errors and solutions

Error: 401 UnauthorizedSolution: Verify that your API key is correct and properly set in the environment variable. Make sure you’re using a valid API key from your Resend Dashboard.
Error: 422 Unprocessable Entity - Invalid from addressSolution: The From field must use a domain you’ve verified in Resend. You can use [email protected] for testing, or add and verify your own domain in the Domains section.
Error: 429 Too Many RequestsSolution: You’ve exceeded your rate limit. The SDK provides rate limit information in the error response. Wait for the specified retry-after period before sending more emails, or upgrade your plan for higher limits.
Error: context deadline exceededSolution: The request took too long to complete. The default HTTP client has a 1-minute timeout. You can create a custom HTTP client with a longer timeout if needed, or check your network connection.

Next steps

Now that you’ve sent your first email, explore more advanced features:

Email templates

Create reusable email templates with variables

Schedule emails

Schedule emails for future delivery

Webhooks

Receive real-time email event notifications

Manage contacts

Organize contacts into audiences and segments

Build docs developers (and LLMs) love