Prompt
building an email API integration in Go
Latest observation
Oct 8, 2026
OpenAI APIWeb search: off
Sure — if you’re building an email API integration in Go, the typical approach is:
-
Pick an email provider
Common choices:- SendGrid
- Mailgun
- Postmark
- AWS SES
- Gmail/Outlook SMTP for simpler setups
-
Decide whether to use:
- HTTP API (recommended for most providers)
- SMTP (simpler, but usually less feature-rich)
-
Build a small Go package around sending emails
Here’s a clean example using a generic HTTP-style API pattern in Go.
Example: Email sender interface
package email
import "context"
type Sender interface {
Send(ctx context.Context, to, subject, body string) error
}
Example: SendGrid-style implementation
package email
import (
"bytes"
"context"
"encoding/json"
"fmt"
"net/http"
)
type SendGridSender struct {
APIKey string
From string
Client *http.Client
}
type sendGridRequest struct {
Personalizations []struct {
To []struct {
Email string `json:"email"`
} `json:"to"`
} `json:"personalizations"`
From struct {
Email string `json:"email"`
} `json:"from"`
Subject string `json:"subject"`
Content []struct {
Type string `json:"type"`
Value string `json:"value"`
} `json:"content"`
}
func (s *SendGridSender) Send(ctx context.Context, to, subject, body string) error {
if s.Client == nil {
s.Client = http.DefaultClient
}
var reqBody sendGridRequest
reqBody.Personalizations = []struct {
To []struct {
Email string `json:"email"`
} `json:"to"`
}{
{
To: []struct {
Email string `json:"email"`
}{{Email: to}},
},
}
reqBody.From.Email = s.From
reqBody.Subject = subject
reqBody.Content = []struct {
Type string `json:"type"`
Value string `json:"value"`
}{
{Type: "text/plain", Value: body},
}
data, err := json.Marshal(reqBody)
if err != nil {
return err
}
req, err := http.NewRequestWithContext(ctx, http.MethodPost, "https://api.sendgrid.com/v3/mail/send", bytes.NewReader(data))
if err != nil {
return err
}
req.Header.Set("Authorization", "Bearer "+s.APIKey)
req.Header.Set("Content-Type", "application/json")
resp, err := s.Client.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode >= 300 {
return fmt.Errorf("sendgrid send failed: status %s", resp.Status)
}
return nil
}
Usage
package main
import (
"context"
"log"
"time"
"yourmodule/email"
)
func main() {
sender := &email.SendGridSender{
APIKey: "your-api-key",
From: "no-reply@example.com",
}
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
err := sender.Send(ctx, "user@example.com", "Welcome!", "Thanks for signing up.")
if err != nil {
log.Fatal(err)
}
}
Good practices for an email integration
- Use a dedicated package for email logic
- Add retries for transient failures
- Validate recipient email addresses
- Support both plain text and HTML
- Log failures with context, but avoid logging sensitive content
- Make sender configurable via env vars
- Add rate limiting if sending in bulk
- Use a queue/background worker for large volumes
If you want SMTP instead
If your provider supports SMTP, Go’s net/smtp or a better-maintained library like gopkg.in/gomail.v2 can be used. SMTP is good for straightforward sending, but HTTP APIs usually give better deliverability tools, analytics, and templates.
If you want, I can also give you:
- a SendGrid / Mailgun / SES-specific Go example
- a production-ready email package structure
- an example with HTML templates + attachments
- a Go SMTP implementation