Case Study

Email Campaign and Subscriber Management

An email marketing platform for managing consent, scheduling campaigns and controlling delivery.

This email marketing platform gives operators one place to prepare campaigns, keep subscriber lists in order and watch how mail goes out. Operators handle lists and content in the admin screens, while the mail itself travels through SMTP services the team sets up.

The client sends two kinds of mail from it: newsletters and transactional messages. Imports and audience selection feed each send, and scheduling and bounce handling wrap around it. Because address upkeep sits next to the campaigns, each list stays current for the mail that uses it.

The challenge

One address can be subscribed to a list and unsubscribed from another. Those choices have to hold when a campaign picks its audience. Once sending starts, the campaign also respects delivery limits and notes failures, so the next send works from fresh data.

Pausing a large campaign is harder than stopping a loop. Some messages are already prepared, and some are in flight. We needed the saved progress to count that work before a manager chose where to pick the campaign back up again.

What we built

People can join a list through public forms, with double opt-in as an option. Each membership record marks whether an address is unconfirmed, confirmed or unsubscribed, so a choice on one list does not change the others.

Operators import subscriber data and keep custom attributes on each contact. Messages can be composed as visual blocks or rich text, and the same editor also takes Markdown, HTML and plain text. Test sends and attachments help during setup. Scheduling, pause and resume controls then take over once delivery begins.

Transactional messages pull from stored templates through an API. A campaign message can carry an unsubscribe link built for each recipient, plus a one-click unsubscribe header. Operators also decide how much to track. The options run from each person's activity to totals only or no tracking at all.

Bounded work and delivery limits

Setting a campaign to running updates its row in the database. A background manager picks up work that is due, pulls subscribers in batches and renders each personalised message into a queue of fixed size.

Each worker applies the set message rate before calling the delivery service. A full queue makes preparation wait until those workers free space. The campaign pauses by itself once send errors pass the limit, and the manager checks for a stopped campaign before any queued message goes out.

Checkpoints close to the stored audience

Campaign progress lives in PostgreSQL, right beside the audience it tracks. To resume a paused campaign, the manager reads which messages are still in flight and decides where work can start again.

The checkpoint lets a campaign carry on after a pause. A hard crash can still leave delivery uncertain, so it is not an exactly-once guarantee. One sending manager stays active at a time, and other instances answer web requests without sending the same campaign twice.

Subscriber rules and bounce feedback

Audience filters run through a guarded SQL path. The tool reads the query plan first and then runs the query in a read-only transaction, which limits the tables that segmentation can reach.

Bounces come back through a watched mailbox or through provider callbacks. Identifiers in the message headers tie each bounce to its campaign and subscriber. The team sets a bounce limit, and once an address passes it, the rules can unsubscribe, block or delete it.

Project success

Operators can build and schedule a campaign that respects each list's subscription choices, then pause or resume it from recorded progress. Sending workers hold the rate limits. Bounce rules and unsubscribe actions update the addresses that later campaigns will use.

Transactional messages still come from stored templates through the API, while the connected infrastructure handles delivery. The client runs single campaigns and transactional sends here. A nurturing sequence that spans several campaigns belongs in a separate automation process.

Technology stack

Application

Go, Echo

Database

PostgreSQL, sqlx

Interface

Go templates, Alpine.js

Sending

SMTP, HTTP messenger adapters

Background processing

In-process manager and bounded worker queues

Recognize the pattern?

If one of these looks like your situation, the discovery call is where we find out how close.