Post-Purchase Follow-Up Automation in AcelleMail — Thank, Review, Cross-Sell

A confirmation email is just the start. Layer in a delivery-day check-in, a 7-day review request, a 30-day cross-sell, a 60-day "we miss you". This guide builds the full post-purchase flow in AcelleMail's automation builder using tags or custom events fired from your ecommerce backend.

What "post-purchase" actually means

A post-purchase flow is a sequence of emails that fires AFTER someone buys — automatically, without you scheduling each send. The right flow varies by what you sell, but every successful one shares the same skeleton:

Stage Timing Goal
Confirmation Immediately Reassure: order received, here's what happens next
Shipping notification When tracking is available Set expectation for arrival
Delivery check-in 1-2 days after delivery Confirm satisfaction, surface issues early
Review request 7 days after delivery Capture social proof while memory is fresh
Cross-sell / replenishment 30 days after purchase Right-time the next-purchase nudge
Win-back 60-90 days if no return purchase Re-engage before they forget

AcelleMail's automation builder handles all of this with three trigger types: Tag added, Custom event, and Date relative (post-tag).

Setup: two paths depending on your ecommerce stack

Path A: Tag-driven (simpler, manual or webhook-pushed)

When a purchase happens, your ecommerce system tags the subscriber in AcelleMail with a tag like purchased-2026-05-19 or just recent-purchaser. The automation triggers on tag add.

Path B: Custom-event-driven (richer, more flexible)

Your ecommerce system fires a custom event with payload like {"event": "purchase_completed", "order_total": 87.50, "products": ["sku-001", "sku-007"]}. The automation triggers on the event + uses payload data in subsequent steps.

For most senders Path A is enough to start. Switch to Path B when you need conditional flows ("if order over $100 → premium review request track; else standard track").

Build the flow (Path A — tag-driven)

Open the visual automation builder

In AcelleMail's left sidebar, click AutomationAutomations. The index lists every automation in this account with its current state:

Automations index

Click New automation in the top-right toolbar. The trigger picker opens:

Trigger picker — pick what starts the automation

For the confirmation email step:

  1. Trigger: Tag added
  2. Tag: recent-purchaser
  3. Action: send the Confirmation email immediately

Drop in the email step, write your confirmation copy. Save. The trigger now fires the email whenever recent-purchaser tag is added to anyone.

Add downstream steps inside the same automation:

[Trigger: tag added 'recent-purchaser']
  →
[Email: Order Confirmation]
  Wait: 3 days
[Email: How's it going? (delivery check-in)]
  Wait: 4 days  (=7 days from purchase)
[Email: Leave a review]
  Wait: 23 days  (=30 days from purchase)
[Email: You might also like...]
  Wait: 30 days  (=60 days from purchase)
[Condition: did NOT purchase again]
  →
[Email: We miss you — here's 10% off]

The visual builder:

Multi-step automation flow

Each "Wait" step is delay-based — AcelleMail queues the next step's send time per-subscriber individually.

Tag-source patterns

The tag recent-purchaser arrives in AcelleMail one of three ways:

Webhook from ecommerce platform

Shopify / WooCommerce / Magento / BigCommerce all send order webhooks. Configure a bridge service (Cloudflare Worker, Zapier, n8n, custom backend) to translate the webhook into an AcelleMail API call:

[Shopify webhook: order/created]
  → bridge service receives
  → POST to https://acellemail.com/api/v1/subscribers/{uid}/tags
    body: { "tags": ["recent-purchaser"] }

The subscriber must already exist in your AcelleMail list (or use the upsert API to create-if-not-exists).

Manual tag-add from the subscriber detail view

For small senders, the easiest path is manual: open the subscriber, Tags section, click Add tagrecent-purchaser:

Subscriber tags UI

Workable for low-volume; not scalable.

CSV import / bulk re-tag

Export today's orders → CSV with email + tags columns → import into AcelleMail via Audience → [list] → Import with the duplicate-handling set to Update. Existing subscribers get the new tag, the automation fires.

Common UI signals + fixes

Symptom Likely cause UI fix
Confirmation email doesn't send when order placed Webhook from ecommerce isn't reaching AcelleMail Test the webhook destination URL directly with curl; verify auth header
Subscriber gets confirmation but no follow-ups Wait step not advancing Open automation → check run-log for blocked subscribers (waiting on Wait timer; OR exited automation due to unsubscribe)
Same subscriber gets 3 confirmation emails Tag added 3 times (re-imported 3 times) Switch to "Tag changed to" not "Tag added" — fires only once per state change
Review request fires before delivery "7 days from tag add" but tag was added at order time, before shipping Have ecommerce add a separate "order-delivered" tag when tracking shows delivered; trigger review on that tag instead
Cross-sell email recommends item already purchased Email body hard-codes product list, ignores purchase history Use merge tags from custom fields populated at purchase time, OR fall back to popular-items

Path B — Custom event triggers

Switch to events when the flow needs to react to what was purchased, not just that a purchase happened.

Fire the event from your ecommerce backend:

curl -X POST "https://acellemail.com/api/v1/events" \
  -H "Authorization: Bearer $ACELLE_TOKEN" \
  -d '{
    "subscriber_email": "buyer@example.com",
    "event": "purchase_completed",
    "data": {
      "order_total": 87.50,
      "currency": "USD",
      "products": ["yoga-mat-blue", "yoga-block-pair"],
      "category": "fitness"
    }
  }'

In AcelleMail, build the automation:

  1. Trigger: Custom event, event name = purchase_completed
  2. Conditional step: branch on data.order_total > 100
  3. Branch A (high-value): premium review request track
  4. Branch B (standard): standard review request track

Custom-event triggers let the automation read the event's payload — {{ event.data.order_total }} works in email body, {{ event.data.products[0] }} for the product name in subject, etc.

Advanced: ecommerce webhook setups for Shopify, WooCommerce, Stripe

The bridge between your store and AcelleMail is where most "post-purchase doesn't fire" bugs hide. Here are concrete patterns for the three most common platforms.

Shopify → AcelleMail:

# 1. In Shopify admin: Settings → Notifications → Webhooks → Create webhook
#    Event: Order creation
#    Format: JSON
#    URL: https://your-bridge.example.com/shopify-to-acelle

# 2. Your bridge service (Cloudflare Worker example):
addEventListener('fetch', event => {
  event.respondWith(handle(event.request))
})

async function handle(req) {
  if (req.method !== 'POST') return new Response('', { status: 405 })

  // Verify Shopify HMAC signature
  const body = await req.text()
  const sig = req.headers.get('x-shopify-hmac-sha256')
  const expected = await hmacSha256(body, env.SHOPIFY_WEBHOOK_SECRET)
  if (sig !== expected) return new Response('Bad signature', { status: 401 })

  const order = JSON.parse(body)

  // Push to AcelleMail
  await fetch('https://acellemail.com/api/v1/events', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer ' + env.ACELLE_TOKEN,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      subscriber_email: order.email,
      event: 'purchase_completed',
      data: {
        order_total: order.total_price,
        currency: order.currency,
        products: order.line_items.map(l => l.sku),
      }
    })
  })

  return new Response('ok')
}

The verify HMAC step is critical — without it anyone can spoof a Shopify webhook and trigger your automation.

WooCommerce → AcelleMail (via WordPress action hook):

add_action('woocommerce_order_status_completed', function($order_id) {
    $order = wc_get_order($order_id);
    $email = $order->get_billing_email();
    $total = $order->get_total();

    wp_remote_post('https://acellemail.com/api/v1/events', [
        'headers' => [
            'Authorization' => 'Bearer ' . ACELLE_TOKEN,
            'Content-Type' => 'application/json',
        ],
        'body' => json_encode([
            'subscriber_email' => $email,
            'event' => 'purchase_completed',
            'data' => [
                'order_total' => $total,
                'products' => array_map(fn($i) => $i->get_product()->get_sku(), $order->get_items()),
            ]
        ]),
    ]);
});

Add to your theme's functions.php or a custom plugin.

Stripe Subscriptions → AcelleMail:

# Stripe sends 'customer.subscription.created' / 'customer.subscription.updated' / 'invoice.paid'
# Forward via Stripe webhook → your endpoint:

# Express.js example
app.post('/stripe-to-acelle', express.raw({type: 'application/json'}), async (req, res) => {
  const sig = req.headers['stripe-signature'];
  let event;
  try {
    event = stripe.webhooks.constructEvent(req.body, sig, STRIPE_WEBHOOK_SECRET);
  } catch (err) { return res.status(400).send('webhook error'); }

  if (event.type === 'invoice.paid') {
    const invoice = event.data.object;
    await fetch('https://acellemail.com/api/v1/events', {
      method: 'POST',
      headers: {
        'Authorization': 'Bearer ' + ACELLE_TOKEN,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        subscriber_email: invoice.customer_email,
        event: 'subscription_renewed',
        data: { amount: invoice.amount_paid / 100, currency: invoice.currency },
      }),
    });
  }

  res.json({received: true});
});

Reverse-direction sync (AcelleMail → CRM):

When the post-purchase flow's "review request" comes back with a 1-star NPS, you want a sales / customer-success ticket to open in your CRM. Use AcelleMail's automation Send webhook action:

[Form submission: NPS feedback]
  Condition: score <= 6
    [Send webhook: POST https://your-crm.example.com/tickets
       body: { customer_email: '{{ subscriber.email }}', issue: 'low_nps', score: '{{ form.nps_score }}' }]

Your CRM receives, opens a ticket, assigns to a CSM. The whole loop closes without anyone manually copy-pasting.

Replenishment timing — when to nudge the next purchase:

Most products have a "natural reorder cycle" — coffee at 4 weeks, supplements at 30 days, razors at 6 weeks. Set the cross-sell Wait step to ~80% of the typical cycle so the email arrives before they think about reordering, not after they've already gone to a competitor. For unknown products, default to 30 days and measure CTR by Wait-duration A/B test (split the audience: 21d vs 30d vs 45d, compare conversion).

Test the full flow before launching:

In AcelleMail, the automation Test button (or Preview run) lets you simulate a subscriber going through the entire flow with shortened wait times — useful before launching for real.

# Manual test from API:
curl -X POST "https://acellemail.com/api/v1/events" \
  -H "Authorization: Bearer $ACELLE_TEST_TOKEN" \
  -d '{
    "subscriber_email": "your-test-email@example.com",
    "event": "purchase_completed",
    "data": {"order_total": 87.50}
  }'

Then watch the automation logs to verify each step ran + when.

Related articles

10 コメント

コメント 5 件

  1. hung.nguyen.it
    what's the max number of steps in a sequence before performance becomes a concern? Asking because we have a 14-step nurture and I'm wondering if it's overkill.
    1. admin
      We tested this with up to 1M subscribers on a $40/mo VPS. Past that you start needing query optimization. Below that, the defaults are fine
  2. rafa.silva.br
    Built a 9-email welcome series last quarter using this pattern. Took 4 days end-to-end. Open rate on email 1 is 62%, drops to 28% by email 9 — which is actually higher engagement than our broadcast list. Highly recommend the format
    1. admin
      Useful context. The fact that it took 3 weeks end-to-end is realistic; we sometmes get pushed to say 1-week timelines and they're not honest.
  3. i.rossi.mil
    how do you handle subscribers who join mid-sequence (e.g. via api)? do they start at step 1 or pick up at a current point?
    1. admin
      Same answer as above for SaaS-tenant — works the same way per-tenant, with the caveat that the cron must be set per-customer (not just system-ide).
  4. cw.dev.sh
    the visual flow diagram is exactly what i needed. our welcome series has been a mess of forgotten branches — going to redo it tonight using this as the template.
    1. admin
      Thanks. Pass it along if it helps your team.
  5. danrey.dev
    Solid walkthrough. The conditional-branching example especially — most automation guides skip that and you end up rebuilding from scratch.
    1. admin
      Thanks for the kind words. We try to keep these source-grounded so they age well.

More in Automation