sendgrid

package
v1.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 12, 2026 License: MIT Imports: 6 Imported by: 0

Documentation

Overview

Package sendgrid provides a SendGrid API-based email provider for the gomail library.

Overview

The SendGrid provider allows you to send emails using the SendGrid API instead of SMTP. This is particularly useful for high-volume sending, advanced analytics, and when you need features like click tracking and email validation.

SendGrid Account Setup

To use this provider, you need:

1. A SendGrid account (https://sendgrid.com) 2. An API key with "Mail Send" permissions 3. A verified sender email address or domain

Creating an API Key:

  • Log in to SendGrid dashboard
  • Navigate to Settings > API Keys
  • Click "Create API Key"
  • Select "Restricted Access" and enable "Mail Send" permission
  • Copy the API key (starts with "SG.") - you won't be able to see it again

Verifying Sender Identity:

  • Navigate to Settings > Sender Authentication
  • Either verify a single sender email OR authenticate your entire domain
  • Domain authentication is recommended for production use

Configuration

The SendGrid provider requires minimal configuration:

config := sendgrid.Config{
    APIKey:   "SG.xxxxxxxxxxxxxxxxxxxxx",  // Your SendGrid API key
    From:     "noreply@example.com",       // Verified sender email
}

Security Best Practices

API keys should NEVER be hardcoded. Use one of these approaches:

Environment Variables (Development):

config := sendgrid.Config{
    APIKey: os.Getenv("SENDGRID_API_KEY"),
    From:   os.Getenv("SENDGRID_FROM_EMAIL"),
}

Docker Secrets (Production):

apiKey, _ := os.ReadFile("/run/secrets/sendgrid_api_key")
fromEmail, _ := os.ReadFile("/run/secrets/sendgrid_from_email")

config := sendgrid.Config{
    APIKey: strings.TrimSpace(string(apiKey)),
    From:   strings.TrimSpace(string(fromEmail)),
}

Database Storage:

Store encrypted API keys in your database and decrypt at runtime using a separate encryption key stored as a secret.

Basic Usage

package main

import (
    "context"
    "log"
    "os"

    "github.com/ftrinciante/gomail"
    "github.com/ftrinciante/gomail/provider/sendgrid"
)

func main() {
    // Create SendGrid provider
    provider := sendgrid.New(sendgrid.Config{
        APIKey: os.Getenv("SENDGRID_API_KEY"),
        From:   "noreply@example.com",
    })

    // Create client
    client := gomail.NewClient(provider)
    defer client.Close()

    // Create message
    msg := &gomail.Message{
        To:      []string{"user@example.com"},
        Subject: "Hello from SendGrid",
        Body:    "<h1>Welcome!</h1><p>This email was sent via SendGrid.</p>",
        IsHTML:  true,
    }

    // Send email
    if err := client.Send(context.Background(), msg); err != nil {
        log.Fatalf("Failed to send email: %v", err)
    }

    log.Println("Email sent successfully via SendGrid!")
}

With Queue and Templates

SendGrid provider works seamlessly with queues and templates:

// Create Redis queue
queue := redis.New(redisClient, redis.Config{
    QueueKey:   "emails:sendgrid:outbox",
    MaxRetries: 3,
    RetryDelay: 5 * time.Minute,
})

// Create client with SendGrid, queue, and templates
client := gomail.NewClient(
    sendgrid.New(sendgrid.Config{
        APIKey: os.Getenv("SENDGRID_API_KEY"),
        From:   "noreply@example.com",
    }),
    gomail.WithQueue(queue),
    gomail.WithTemplates("./templates/*.html"),
)

// Send templated email asynchronously
client.SendFromTemplateAsync(ctx, "welcome.html", to, subject, data)

// Process queue in background
go client.ProcessQueue(ctx)

Error Handling

SendGrid-specific errors are wrapped in gomail.SendError:

if err := client.Send(ctx, msg); err != nil {
    if sendErr, ok := err.(*gomail.SendError); ok {
        log.Printf("Provider: %s", sendErr.Provider)  // "sendgrid"
        log.Printf("Message: %s", sendErr.Message)
        log.Printf("Underlying error: %v", sendErr.Unwrap())
    }
}

Common errors:

  • Invalid API key: Check your API key starts with "SG." and has Mail Send permission
  • Unverified sender: Verify your sender email or domain in SendGrid dashboard
  • Rate limiting: SendGrid has rate limits based on your plan tier
  • API errors: HTTP 4xx/5xx responses from SendGrid API

When to Use SendGrid vs SMTP

Use SendGrid when you need:

  • High-volume sending (>10,000 emails/month)
  • Advanced analytics and click tracking
  • Better deliverability for transactional emails
  • Email validation and list cleaning
  • Webhook support for delivery events
  • No need to manage SMTP infrastructure

Use SMTP when you:

  • Send low volumes (<1,000 emails/month)
  • Use an existing email server (Gmail, Outlook, etc.)
  • Need maximum control over email infrastructure
  • Want to avoid third-party dependencies
  • Have strict data privacy requirements (emails never leave your infrastructure)

Rate Limits and Pricing

SendGrid rate limits depend on your plan:

  • Free: 100 emails/day
  • Essentials: starts at $19.95/month for 50,000 emails
  • Pro: Custom pricing for higher volumes

The provider automatically handles API responses and errors, but you should implement retry logic using gomail's queue system for production use.

Migration from SMTP

Switching from SMTP to SendGrid is straightforward:

// Before (SMTP)
provider := smtp.New(smtp.Config{
    Host:     "smtp.gmail.com",
    Port:     587,
    Username: "user@gmail.com",
    Password: "app-password",
    From:     "user@gmail.com",
    UseTLS:   true,
})

// After (SendGrid)
provider := sendgrid.New(sendgrid.Config{
    APIKey: os.Getenv("SENDGRID_API_KEY"),
    From:   "noreply@example.com",
})

All other code remains the same - the gomail.Message format and client usage are identical.

Additional Resources

Provider Templates

For more provider-specific configurations, see PROVIDER-TEMPLATES.md in the project root.

Example

Example demonstrates basic SendGrid usage.

package main

import (
	"context"
	"log"
	"os"

	"github.com/ftrinciante/gomail"
	"github.com/ftrinciante/gomail/provider/sendgrid"
)

func main() {
	// Create SendGrid provider
	provider := sendgrid.New(sendgrid.Config{
		APIKey: os.Getenv("SENDGRID_API_KEY"),
		From:   "noreply@example.com",
	})

	// Create client
	client := gomail.NewClient(provider)
	defer client.Close()

	// Create message
	msg := &gomail.Message{
		To:      []string{"user@example.com"},
		Subject: "Hello from SendGrid",
		Body:    "<h1>Welcome!</h1><p>This email was sent via SendGrid.</p>",
		IsHTML:  true,
	}

	// Send email
	if err := client.Send(context.Background(), msg); err != nil {
		log.Fatalf("Failed to send email: %v", err)
	}

	log.Println("Email sent successfully via SendGrid!")
}
Example (CcAndBcc)

Example_ccAndBcc demonstrates using CC and BCC.

package main

import (
	"context"
	"log"
	"os"

	"github.com/ftrinciante/gomail"
	"github.com/ftrinciante/gomail/provider/sendgrid"
)

func main() {
	provider := sendgrid.New(sendgrid.Config{
		APIKey: os.Getenv("SENDGRID_API_KEY"),
		From:   "noreply@example.com",
	})

	client := gomail.NewClient(provider)
	defer client.Close()

	msg := &gomail.Message{
		To:      []string{"primary@example.com"},
		CC:      []string{"manager@example.com"},
		BCC:     []string{"archive@example.com"},
		Subject: "Team Update",
		Body:    "This is a team notification.",
		IsHTML:  false,
	}

	if err := client.Send(context.Background(), msg); err != nil {
		log.Fatalf("Failed to send: %v", err)
	}
}
Example (CustomHeaders)

Example_customHeaders demonstrates adding custom headers.

package main

import (
	"context"
	"log"
	"os"

	"github.com/ftrinciante/gomail"
	"github.com/ftrinciante/gomail/provider/sendgrid"
)

func main() {
	provider := sendgrid.New(sendgrid.Config{
		APIKey: os.Getenv("SENDGRID_API_KEY"),
		From:   "noreply@example.com",
	})

	client := gomail.NewClient(provider)
	defer client.Close()

	msg := &gomail.Message{
		To:      []string{"user@example.com"},
		Subject: "Custom Headers",
		Body:    "This email has custom headers.",
		IsHTML:  false,
		Headers: map[string]string{
			"X-Priority":    "1",
			"X-Application": "MyApp",
			"X-User-ID":     "12345",
		},
	}

	if err := client.Send(context.Background(), msg); err != nil {
		log.Fatalf("Failed to send: %v", err)
	}
}
Example (DockerSecrets)

Example_dockerSecrets demonstrates loading config from Docker secrets.

package main

import (
	"context"
	"log"
	"os"

	"github.com/ftrinciante/gomail"
	"github.com/ftrinciante/gomail/provider/sendgrid"
)

func main() {
	// Read API key from Docker secret
	apiKeyBytes, err := os.ReadFile("/run/secrets/sendgrid_api_key")
	if err != nil {
		log.Fatalf("Failed to read API key secret: %v", err)
	}

	// Read from email from Docker secret
	fromEmailBytes, err := os.ReadFile("/run/secrets/sendgrid_from_email")
	if err != nil {
		log.Fatalf("Failed to read from email secret: %v", err)
	}

	provider := sendgrid.New(sendgrid.Config{
		APIKey: string(apiKeyBytes),
		From:   string(fromEmailBytes),
	})

	client := gomail.NewClient(provider)
	defer client.Close()

	msg := &gomail.Message{
		To:      []string{"user@example.com"},
		Subject: "Docker Secrets",
		Body:    "Configuration loaded from Docker secrets.",
		IsHTML:  false,
	}

	if err := client.Send(context.Background(), msg); err != nil {
		log.Fatalf("Failed to send: %v", err)
	}
}
Example (EnvironmentConfig)

Example_environmentConfig demonstrates loading config from environment.

package main

import (
	"context"
	"log"
	"os"

	"github.com/ftrinciante/gomail"
	"github.com/ftrinciante/gomail/provider/sendgrid"
)

func main() {
	// Load configuration from environment variables
	config := sendgrid.Config{
		APIKey: os.Getenv("SENDGRID_API_KEY"),
		From:   os.Getenv("SENDGRID_FROM_EMAIL"),
	}

	// Validate required config
	if config.APIKey == "" {
		log.Fatal("SENDGRID_API_KEY environment variable is required")
	}
	if config.From == "" {
		log.Fatal("SENDGRID_FROM_EMAIL environment variable is required")
	}

	provider := sendgrid.New(config)
	client := gomail.NewClient(provider)
	defer client.Close()

	msg := &gomail.Message{
		To:      []string{"user@example.com"},
		Subject: "Environment Config",
		Body:    "Configuration loaded from environment variables.",
		IsHTML:  false,
	}

	if err := client.Send(context.Background(), msg); err != nil {
		log.Fatalf("Failed to send: %v", err)
	}
}
Example (ErrorHandling)

Example_errorHandling demonstrates proper error handling.

package main

import (
	"context"
	"log"
	"os"

	"github.com/ftrinciante/gomail"
	"github.com/ftrinciante/gomail/provider/sendgrid"
)

func main() {
	provider := sendgrid.New(sendgrid.Config{
		APIKey: os.Getenv("SENDGRID_API_KEY"),
		From:   "noreply@example.com",
	})

	client := gomail.NewClient(provider)
	defer client.Close()

	msg := &gomail.Message{
		To:      []string{"user@example.com"},
		Subject: "Test",
		Body:    "Test email",
		IsHTML:  false,
	}

	if err := client.Send(context.Background(), msg); err != nil {
		// Check if it's a SendError
		if sendErr, ok := err.(*gomail.SendError); ok {
			log.Printf("Provider: %s", sendErr.Provider)
			log.Printf("Error: %s", sendErr.Message)
			if sendErr.Err != nil {
				log.Printf("Underlying error: %v", sendErr.Err)
			}
		} else {
			log.Printf("Unexpected error: %v", err)
		}
		return
	}

	log.Println("Email sent successfully!")
}
Example (HtmlEmail)

Example_htmlEmail demonstrates sending HTML emails.

package main

import (
	"context"
	"log"
	"os"

	"github.com/ftrinciante/gomail"
	"github.com/ftrinciante/gomail/provider/sendgrid"
)

func main() {
	provider := sendgrid.New(sendgrid.Config{
		APIKey: os.Getenv("SENDGRID_API_KEY"),
		From:   "noreply@example.com",
	})

	client := gomail.NewClient(provider)
	defer client.Close()

	html := `
<!DOCTYPE html>
<html>
<head>
    <style>
        .header { background: #007bff; color: white; padding: 20px; }
        .content { padding: 20px; }
    </style>
</head>
<body>
    <div class="header">
        <h1>Welcome to Our Service!</h1>
    </div>
    <div class="content">
        <p>Thank you for signing up.</p>
        <a href="https://example.com">Get Started</a>
    </div>
</body>
</html>
	`

	msg := &gomail.Message{
		To:      []string{"newuser@example.com"},
		Subject: "Welcome Aboard!",
		Body:    html,
		IsHTML:  true,
	}

	if err := client.Send(context.Background(), msg); err != nil {
		log.Fatalf("Failed to send: %v", err)
	}
}

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Config

type Config struct {
	// APIKey is the SendGrid API key (starts with "SG.")
	APIKey string

	// From is the default sender email address
	// This email must be verified in SendGrid
	From string
}

Config holds the SendGrid API configuration.

type Provider

type Provider struct {
	// contains filtered or unexported fields
}

Provider is the SendGrid email provider implementation.

func New

func New(config Config) *Provider

New creates a new SendGrid provider with the given configuration.

func (*Provider) Send

func (p *Provider) Send(ctx context.Context, msg *gomail.Message) error

Send sends an email message via SendGrid API.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL
⌂ 换网址