package mailer
import (
"crypto/sha256"
"encoding/hex"
"strings"
)
type Email struct {
To string
Template string
DedupeKey string
Body string
}
// Fingerprint derives a stable identity for a logically-unique email.
// Body is intentionally excluded so volatile content does not break equality.
func Fingerprint(e Email) string {
parts := []string{
strings.ToLower(strings.TrimSpace(e.To)),
e.Template,
e.DedupeKey,
}
sum := sha256.Sum256([]byte(strings.Join(parts, "\x00")))
return "email:fp:" + hex.EncodeToString(sum[:])
}
package mailer
import (
"context"
"time"
"github.com/redis/go-redis/v9"
)
type Deduper struct {
rdb *redis.Client
ttl time.Duration
}
func NewDeduper(rdb *redis.Client, ttl time.Duration) *Deduper {
return &Deduper{rdb: rdb, ttl: ttl}
}
// Reserve atomically claims fp. It returns true only if this caller
// won the slot; false means another send already reserved it.
func (d *Deduper) Reserve(ctx context.Context, fp string) (bool, error) {
return d.rdb.SetNX(ctx, fp, "1", d.ttl).Result()
}
// Release frees a reservation so a legitimate retry can proceed.
func (d *Deduper) Release(ctx context.Context, fp string) error {
return d.rdb.Del(ctx, fp).Err()
}
package mailer
import (
"context"
"errors"
"fmt"
)
var ErrDuplicate = errors.New("mailer: duplicate email suppressed")
type Sender interface {
Send(ctx context.Context, e Email) error
}
type Mailer struct {
dedupe *Deduper
smtp Sender
}
func NewMailer(dedupe *Deduper, smtp Sender) *Mailer {
return &Mailer{dedupe: dedupe, smtp: smtp}
}
func (m *Mailer) Send(ctx context.Context, e Email) error {
fp := Fingerprint(e)
claimed, err := m.dedupe.Reserve(ctx, fp)
if err != nil {
return fmt.Errorf("reserve fingerprint: %w", err)
}
if !claimed {
return ErrDuplicate
}
sent := false
defer func() {
if !sent {
_ = m.dedupe.Release(ctx, fp)
}
}()
if err := m.smtp.Send(ctx, e); err != nil {
return fmt.Errorf("smtp send: %w", err)
}
sent = true
return nil
}
This snippet shows a small, focused pattern for preventing duplicate outbound emails when the same send request can arrive more than once — a common problem with at-least-once queues, retried HTTP handlers, and re-run cron jobs. The core idea is to compute a stable fingerprint for each email and record it in a Redis set (technically a set of keys with TTL) so that a second attempt with the same fingerprint is skipped before the message ever reaches the SMTP provider.
In the fingerprint tab, Fingerprint derives a deterministic key from the fields that define a logically-identical email: recipient, template, and a caller-supplied DedupeKey. Using DedupeKey rather than the full rendered body matters because bodies often contain timestamps or tracking pixels that would break equality; the caller decides what "the same email" means. The value is hashed with SHA-256 and hex-encoded so the Redis key stays fixed-length and safe regardless of address length.
The Deduper tab wraps the actual guard. Reserve uses SET key value NX PX ttl, which atomically claims the fingerprint only if it does not already exist. This single round-trip is the crux of the pattern: the check and the claim happen together, so two concurrent workers cannot both pass the guard. A true return means this caller won the race and should send; false means another attempt already reserved it. Release exists for the failure path — if sending errors out, the reservation is deleted so a legitimate retry can proceed rather than being silently swallowed.
The Mailer tab ties it together. Send computes the fingerprint, calls Reserve, and short-circuits with ErrDuplicate when the slot is taken. Crucially it uses defer with a flag so that if smtp.Send fails, Release is called and the fingerprint is freed. The chosen TTL is a deliberate trade-off: long enough to cover realistic retry windows and duplicate bursts, short enough that Redis memory does not grow unbounded and that a genuinely-new email after the window is not blocked. Callers that need stronger guarantees can persist fingerprints in sql instead, but Redis keeps the hot path fast.
Related snips
export interface RetryOptions {
retries: number;
baseMs: number;
maxMs: number;
signal?: AbortSignal;
onRetry?: (attempt: number, delay: number, err: unknown) => void;
Exponential backoff with jitter for retries
package dbutil
import (
"context"
"github.com/jackc/pgconn"
Retry Postgres serialization failures with bounded attempts
// Creating a Promise
const myPromise = new Promise((resolve, reject) => {
const success = true;
setTimeout(() => {
if (success) {
Promises and async/await patterns for asynchronous JavaScript
use crossbeam::channel::unbounded;
use std::thread;
fn main() {
let (tx, rx) = unbounded();
Crossbeam for advanced concurrent data structures
use std::sync::mpsc;
use std::thread;
fn main() {
let (tx, rx) = mpsc::channel();
Channels (mpsc) for message passing between threads
export type Settled<R> =
| { status: 'fulfilled'; value: R }
| { status: 'rejected'; reason: unknown };
export interface ConcurrencyOptions {
limit: number;
Simple concurrency limiter for batch operations
Share this code
Here's the card — post it anywhere.