Field SOP
Field SOP

Email Marketing Automation Workflow: A/B Self-Optimization

An n8n workflow for email marketing automation: scheduled pull of subscribers -> segment by tag/behavior -> LLM generates A/B personalized emails (subject + body) per segment -> SMTP send -> Webhook tracks opens/clicks -> write back metrics -> IF open rate below threshold with sufficient sample -> trigger LLM copy regeneration. Includes compliance notes (subscribed/authorized only, one-click unsubscribe, CAN-SPAM/GDPR/E-Commerce Law, no sensitive-attribute inference). Includes a .json template download.

Published August 4, 20265 min read
<!-- workflow-email-marketing-automation | resource | Email Marketing Automation Workflow: A/B Self-Optimization -->

The biggest waste in bulk email isn't that nobody opens it-it's that you've already collected subscription tags and behavior data, yet you send every user the same identical copy. Active subscribers find the content dull and go cold. New subscribers get an off-cycle old topic in their very first email and churn on the spot. Manual segmentation, per-segment copywriting, and A/B testing are three layers of repeated toil: export the list, filter by tag, copy-paste subject lines, send, wait two days for open rates, then rewrite and resend. Two sends a week eat all your time, let alone judging "was it the subject line or the body?" after a low open rate-by gut, with nothing learned.

This n8n workflow chains "segment -> generate personalized email -> A/B send -> track opens/clicks -> write back metrics -> auto-regenerate copy on low open rate" into one automated line. A weekly trigger pulls subscribers from your CRM or Feishu Bitable, segments them by tag and recent behavior, and an LLM generates A/B variants (subject + body) per segment, each sent to half the list. Emails embed tracking links; opens and clicks flow back through a Webhook. When the open rate drops below a threshold with a sufficient sample, an LLM auto-generates fresh candidate copy for the next A/B round. It complements this site's Lead Auto-Collection, Scoring & Notification Workflow (workflow-lead-crm-automation)-that workflow owns acquisition, this one owns retention and reach. Email content can pull high-scoring topics from the RSS-to-AI-Summary Content Pipeline Workflow (workflow-rss-content-pipeline), keeping newsletters and site posts sourced from the same pipeline for smoother funneling.

Compliance note: email marketing must be compliant. Send only to subscribed/authorized users, include a one-click unsubscribe link in every email, and comply with CAN-SPAM, GDPR, China's E-Commerce Law, and other applicable regulations. Personalization is not a license to abuse user data-avoid inferring or price-differentiating on sensitive attributes like race, health, income, or religion. Respect users on send frequency and timing, and offer a preference center. The segmentation in this workflow uses only subscription tags and public behavior (column preference, recent opens). Always verify against your local regulations before sending.

Workflow Chain

Schedule trigger (every Tuesday 10 AM) -> HTTP Request pulls subscribers from CRM/Feishu table (with tag and behavior fields) -> Code segments by tag + behavior -> LLM node (HTTP Request to DeepSeek/Kimi) generates A/B subject + body per segment -> Code parses JSON and splits the segment list in half (A gets the first half, B the second) -> Send Email (SMTP) sends per variant (emails embed tracking and unsubscribe links) -> HTTP Request writes send records to the metrics table -> [Webhook fires async] track open/click -> HTTP Request pulls that variant's sent and opened counts -> Code computes open rate -> IF open rate < threshold AND sample >= 50 -> HTTP Request calls LLM to regenerate candidate copy and trigger an A/B retest.

Download Template

Setup Steps

  1. Import: n8n -> Workflows -> Import from File, pick workflow-email-marketing-automation.json
  2. Schedule node: set to trigger every Tuesday at 10 AM (Monday for topic selection, Tuesday for sending, leaving room for copy generation). Switch to daily for high-frequency newsletters
  3. Pull subscribers node: fill in your CRM or Feishu Bitable API (Feishu OpenAPI to fetch records with "tag", "recent open", "column preference" fields; Mailchimp/ConvertKit via their HTTP API). Pull only status='subscribed' authorized users-unsubscribed users are excluded at the source
  4. Segment Code node: group by tag (e.g., "AI tools hands-on", "hot takes", "tutorials") and recent behavior (opened in last 30 days = active, else = dormant). Each segment outputs segment / subscribers / count
  5. LLM node: fill in API key (DeepSeek/Kimi/Qwen all work), prompt outputs subjectA / bodyA / subjectB / bodyB (see Companion Prompt below). Body must include a [name] placeholder and an [[unsubscribe]] link placeholder
  6. Parse Code node: split the segment list in half-A gets the first half, B the second-outputting two items (variant / subject / body / recipients / segment). n8n runs downstream nodes once per item
  7. Send Email node: configure SMTP credentials (Gmail / Tencent Exmail / SendGrid all work), fromEmail as a fixed sender, toEmail as an expression aggregating recipient emails, subject/text referencing the current item's variant fields. Body must end with an unsubscribe link
  8. Write send record node: after each variant sends, POST a record to the metrics table (variant / segment / sent / timestamp)-this is the denominator for the open rate calculation
  9. Tracking Webhook node: set path to email-track; the tracking pixel/link in the email body points to https://your-n8n-domain/email-track?variant=A&segment=xxx&event=open. Both opens and clicks hit this Webhook
  10. Pull counts node: GET the cumulative sent and opened counts for that variant from the metrics table
  11. Compute open rate Code node: openRate = opened / sent * 100, outputs variant / sent / opened / openRate / segment
  12. IF node: two AND conditions-openRate < 20 AND sent >= 50 (skip when the sample is too small to avoid misjudging on early events). True branch goes to copy regeneration, false ends
  13. Trigger regeneration node: calls the LLM to regenerate 3 candidate subject + body pairs for the low-open-rate variant (different angles: benefit / urgency / curiosity), writing them back to the copy library for the next A/B round
  14. Test run: manually trigger the Schedule node, verify A and B each went to half the list; curl a simulated Webhook call (with variant=A&event=open) and check whether metrics write back; set sent to 50 and openRate to 10 manually and verify the IF takes the regeneration branch. Confirm the unsubscribe link works and only authorized users are emailed before enabling the schedule

Companion Prompt (LLM Generates A/B Personalized Emails per Segment)

Prompt
You are an email marketing copywriter. Read the subscriber segment below and generate A/B email variants, outputting:
1. subjectA / subjectB: subject lines, ≤50 chars, A leans direct-benefit, B leans curiosity-suspense
2. bodyA / bodyB: body, plain text, ≤300 chars, personalize the greeting with a [name] placeholder, and end with an [[unsubscribe]] link
Constraints:
- Personalize only on segment tags and public behavior (column preference, recent opens); do not infer race/health/income/religion or other sensitive attributes
- Do not fabricate product features or data; leave placeholders for offers and numbers for human confirmation
- Match tone to the segment (tutorials = hands-on, hot takes = time-sensitive)
Output JSON: subjectA, bodyA, subjectB, bodyB.
Segment tag: {{segment}}
Segment size: {{count}}

Advanced

  • Finer segmentation: layer RFM dimensions in the segment Code node-recency (R), open frequency (F), link clicks (M). Carve "dormant high-value users" into their own segment for re-engagement emails instead of regular pushes
  • Send-time optimization: different segments are active at different times. Add a Wait node before Send Email, delaying by each segment's best slot (tutorial fans at 8 PM, hot-take fans at 7 AM)-open rates can shift by several percentage points
  • Metrics write-back loop: after the regeneration node, add a Send Email that sends the new candidate copy to the segment's remaining unopened users (only resend to each user once in a short window to avoid harassment-this is both a compliance and experience requirement)
  • Multi-segment concurrency: the segment Code node outputs multiple items, and the LLM and Send Email run per segment. Watch LLM rate limits-add a Split in Batches node, one segment per batch, to control concurrency
  • Content-site integration: feed the high-scoring topics from the RSS-to-AI-Summary Content Pipeline Workflow (workflow-rss-content-pipeline) into the LLM prompt's context, so email content shares the same source as site posts and funnels better
  • Automated unsubscribe handling: have the Webhook listen for unsubscribe events; on receipt, immediately PATCH the CRM to set that user's status to 'unsubscribed' so subsequent workflow runs exclude them automatically. This is a compliance hard requirement, not optional

Pitfalls

  • Open-rate tracking is inaccurate: email clients block tracking pixels by default, undercounting opens. Click tracking is more reliable than open tracking-prioritize click rate for A/B decisions. Dedupe multiple opens by the same user in the Webhook, or open rates inflate
  • Webhook triggers regeneration on every open: open rate is dynamic; early events swing it wildly. The IF must include a sent >= 50 sample floor. A more robust approach is to run the evaluation on a daily schedule rather than on every single open
  • LLM omits the unsubscribe link: models occasionally drop [[unsubscribe]]. Add a check in the parse Code node-if the body has no unsubscribe token, fail and block it from Send Email
  • SMTP rate limits: Tencent Exmail / Gmail cap daily sends in the hundreds. For large lists, add Split in Batches at 50 per batch with a Wait interval to avoid triggering risk control. For high volume, use a dedicated service like SendGrid / Mailgun
  • Uneven A/B split: when count is odd, half rounds down and B gets one extra. Harmless, but with segment sizes < 100 the A/B sample is too small to be statistically significant-skip A/B and send one variant to the full list
  • Sensitive-attribute inference: the LLM occasionally infers gender or ethnicity from name/region to tailor copy. Hard-constrain it in the prompt and have the parse Code node scan the body for sensitive terms, discarding and regenerating on a hit
  • Unsubscribe link dead: the [[unsubscribe]] placeholder gets sent out unreplaced. Add a Code node before Send Email to replace placeholders with real links, and verify the link is reachable before sending

References

This article is AI-assisted and human-edited. Last updated: 2026-08-04

Related