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 ¶
- SendGrid Documentation: https://docs.sendgrid.com
- API Key Permissions: https://docs.sendgrid.com/ui/account-and-settings/api-keys
- Sender Authentication: https://docs.sendgrid.com/ui/account-and-settings/sender-verification
- Rate Limits: https://docs.sendgrid.com/api-reference/mail-send/limitations
- Pricing: https://sendgrid.com/pricing
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!")
}
Output:
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)
}
}
Output:
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)
}
}
Output:
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)
}
}
Output:
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)
}
}
Output:
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!")
}
Output:
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)
}
}
Output:
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.