Skip to content
Writing
GoGolangMicroservicesResilience

Go (Golang) Microservice for Email with Circuit Breakers & Retries

Learn how to write a production-grade Go service that dispatches millions of emails with resilient circuit breaking, retries, and zero memory leaks.

Tayyab MughalFounder & AI Chief2 min read

Why Go microservices need circuit breakers for external APIs

When downstream third-party networks experience temporary degradation, unbounded goroutines trying to send emails can exhaust system file descriptors and crash your service.

Implementing the Circuit Breaker pattern with sony/gobreaker ensures your Go service fails fast during upstream outages without cascading failures.

Go Email Client with Circuit Breaker (email.go)

Here is the complete Go implementation with circuit breakers and custom JSON transport.

GOLANG
package main

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"time"

	"github.com/sony/gobreaker"
)

type EmailClient struct {
	apiKey     string
	httpClient *http.Client
	cb         *gobreaker.CircuitBreaker
}

type SendRequest struct {
	To      string `json:"to"`
	Subject string `json:"subject"`
	Text    string `json:"text"`
}

func NewEmailClient(apiKey string) *EmailClient {
	st := gobreaker.Settings{
		Name:        "SadaSendCircuitBreaker",
		MaxRequests: 5,
		Interval:    30 * time.Second,
		Timeout:     10 * time.Second,
	}
	return &EmailClient{
		apiKey:     apiKey,
		httpClient: &http.Client{Timeout: 5 * time.Second},
		cb:         gobreaker.NewCircuitBreaker(st),
	}
}

func (c *EmailClient) Send(ctx context.Context, req SendRequest) error {
	_, err := c.cb.Execute(func() (interface{}, error) {
		payload, _ := json.Marshal(req)
		httpReq, _ := http.NewRequestWithContext(ctx, "POST", "https://api.sadasend.com/v1/emails", bytes.NewBuffer(payload))
		httpReq.Header.Set("Authorization", "Bearer "+c.apiKey)
		httpReq.Header.Set("Content-Type", "application/json")

		resp, err := c.httpClient.Do(httpReq)
		if err != nil {
			return nil, err
		}
		defer resp.Body.Close()

		if resp.StatusCode >= 500 {
			return nil, fmt.Errorf("server error: %d", resp.StatusCode)
		}
		return nil, nil
	})
	return err
}

Core Advantages in Go Production Clusters

  • Zero goroutine leakage on connection stalls.
  • Fail-fast protection that recovers automatically when connectivity restores.
  • Native context.Context cancellation support for graceful server shutdowns.
Free plan

Building AI agents that send email?

Scoped API keys, per-key recipient allowlists, approval mode and a hosted MCP server with ten tools — on the free plan, without a card.