SwastikA
OverviewExpertiseWhat I BuiltExperienceDeep Dives
Home→Projects→Advanced Email Marketing Automation
Automation

Advanced Email Marketing Automation

24–48h (manual list export)→<30 secondstrigger-to-delivery latency

The marketing team was forced to rely on massive, unsegmented batch email campaigns scheduled arbitrarily, entirely ignoring where individual users were in their lifecycle. This lack of contextual targeting meant conversion rates were dismal, and users frequently complained about receiving irrelevant messages. The delay between a user action and a relevant email was often 24 to 48 hours because lists had to be manually exported and uploaded to the provider. Furthermore, the system lacked structural safeguards against duplicate sends; when the network timed out during a batch run, the retry logic would blindly resend the entire batch, angering users. The marketing team was completely dependent on engineering to change any campaign logic, severely bottlenecking their ability to iterate.

PythonFlaskSendGrid
← Projects
ON THIS PAGE
// system visuals

See It In Action

LIVE_SYSTEM_PREVIEW
VISUAL_EXPLORER/ analytics_deliverability
Advanced Email Marketing Automation — Analytics deliverability
CATEGORY:Overview
ASSET_ID:analytics_deliverability
# Analytics deliverability
01/02
← → NAVIGATE_SYSTEM
// the problem

What Was Broken

  • ❌Fixed-schedule batch sends completely ignored user behavior, treating highly engaged users exactly the same as inactive ones. Rebuilt the architecture around an event-driven model where specific user actions trigger immediate, relevant sequences.
  • ❌The latency between a significant user action and a relevant communication was typically 24-48 hours. Eliminated manual list exports, ensuring emails land within 30 seconds of the triggering event.
  • ❌Network retries frequently caused duplicate sends, leading to a high volume of user complaints and unsubscribes. Engineered a rigorous idempotency layer that makes duplicate sends structurally impossible, regardless of retry behavior.
  • ❌Marketing could not adapt campaigns or adjust timing without filing an engineering ticket and waiting for a deployment. Abstracted the trigger logic into a configurable rules engine, enabling self-service campaign management.
// required fix
  • The system needed to react instantly to user behavior rather than relying on scheduled batches. The task was to build a robust event listener that consumes action payloads and fires the appropriate sequence without delay.
  • Duplicate sends were damaging the brand's reputation. The objective was to implement strict idempotency keys tied to each specific event, ensuring that retries are handled gracefully as no-ops.
  • Managing local SMTP servers was an unnecessary operational burden. The task required integrating seamlessly with SendGrid to handle high-volume delivery and compliance automatically.
  • Engineering was a bottleneck for marketing agility. The goal was to build a configurable rules engine where non-technical teams could safely manage campaign mappings and delays.
// solution

How It Was Built

The core of the system is a Flask-based event listener that continuously consumes user action payloads from an internal queue. This listener evaluates each event against a configurable rules table, mapping actions to specific email templates and delays, allowing marketing to update campaigns without code changes. To ensure absolute reliability, an idempotency layer was built into the database architecture; every event generates a unique key that is checked before any SendGrid API call is made. This guarantees that even if a message is processed multiple times due to a worker crash or network timeout, the external API is only ever called once.

Event-Based Trigger Engine
  • The legacy system relied on cron jobs running massive SQL queries to find users who met certain criteria, which was slow and unscalable.
  • 📄 trigger_engine.py
Idempotency Layer — Duplicates Eliminated
  • The most damaging flaw in the previous system was its vulnerability to network timeouts.
01

Event-Based Trigger Engine

The legacy system relied on cron jobs running massive SQL queries to find users who met certain criteria, which was slow and unscalable. The solution was to pivot entirely to an event-driven architecture. The core application now publishes granular events (e.g., 'user_signup', 'cart_abandoned') to a lightweight message queue. A dedicated Flask consumer continuously listens to this queue, instantly mapping incoming events to specific email sequences. To remove the engineering bottleneck, this mapping logic was abstracted into a configurable rules table in the database. When the consumer receives an event, it checks the table to determine the correct template and required delay, then schedules the execution. This decoupled architecture meant marketing could instantly adjust a cart abandonment delay from 60 minutes to 30 minutes without a single line of code being touched.

trigger_engine.py
python
class TriggerEngine:
    RULES = {
        'user_signup':      ('welcome',  delay=0),
        'cart_abandoned':   ('recovery', delay=3600),
        'order_completed':  ('receipt',  delay=0),
    }

    def handle_event(self, event: str, user_id: str):
        if event not in self.RULES:
            return
        template, delay = self.RULES[event]
        if self.in_cooldown(user_id, event):
            return
        self.schedule_email(
            user_id=user_id,
            template=template,
            send_at=now() + delay
        )
        self.set_cooldown(user_id, event)
02

Idempotency Layer — Duplicates Eliminated

The most damaging flaw in the previous system was its vulnerability to network timeouts. If a batch send timed out halfway through, the naive retry logic would restart the batch, spamming the first half of the list twice. To solve this definitively, a strict idempotency layer was engineered. For every triggered event, the system generates a unique, deterministic hash composed of the event type, the user ID, and the date. Before the consumer initiates a call to the SendGrid API, it attempts to insert this idempotency key into a highly optimized database table with a unique constraint. If the insert fails because the key already exists, the consumer immediately recognizes the request as a duplicate and safely discards it as a no-op. This architectural guarantee completely eliminated duplicate sends, regardless of how aggressively the queue retried failed jobs.

// results

What Changed

The transition to behavior-triggered sequences fundamentally transformed the communication strategy, completely replacing ineffective batch campaigns. Relevant, highly contextual emails now land in user inboxes within 30 seconds of their triggering action, significantly boosting engagement. By enforcing strict idempotency, user complaints regarding duplicate sends dropped to absolute zero. Furthermore, decoupling the campaign logic empowered the marketing team to iterate independently, drastically accelerating their operational velocity.

Trigger-to-delivery latency
24–48h (manual list export)
→
0
Real-time
Duplicate sends
Recurring user complaint
→
0
Eliminated by idempotency
Campaign adaptability
Requires engineering
→
0
Self-service
"Users get the right email at the right moment — and never twice."
←PREVIOUS PROJECTCorporate Sales Reporting — From Manual Excel to Automated Pipeline
NEXT PROJECTAPI Integration Framework→
© 2025 Swastik Agnihotri — Built with precision.
GitHubLinkedIn