Marketing & email
Email Newsletter Campaigns
Generated from docs/plan/core/email-newsletter-campaigns/PLAN.md in the AstroBaaS repository. Nothing described below is implemented — it is the written plan for it.
A free core feature that lets merchants build and send email newsletters to their subscriber list, with basic templates and open-rate tracking. Paid tiers add segmentation, automation workflows, and multivariate testing.
The problem
Merchants can send transactional order confirmations but have no way to send marketing newsletters to their customer and subscriber list. Currently they manually export subscriber lists to Mailchimp or similar platforms, losing connection to storefront data and customer lifetime value.
What it does
- Subscriber list management (signup form builder, GDPR opt-in/out, bulk import)
- Email template builder with drag-drop blocks (text, images, product grids, buttons)
- Send one-time newsletter to entire subscriber list
- Open rate tracking (pixel-based, per subscriber, per campaign)
- Subscriber segmentation by purchase history (customers only, buyers of specific products)
- Campaign history and re-send capability
- Email rendering and preview (desktop, mobile, dark mode)
- Unsubscribe link handling and GDPR hard-delete on request
- Basic analytics dashboard (send time, open rate, click rate, unsubscribe count)
- Scheduled send (send now or at specific time)
What it deliberately does NOT do
Each boundary carries its reason. A boundary without a reason gets crossed by the next person who reads this.
- Automation workflows (if customer doesn’t purchase in 30 days, send email) — paid module owns logic-flow orchestration; core doesn’t model state machines
- Multivariate A/B testing (requires statistical framework and sample-size tracking) — paid module owns experiment design and validation
- Third-party integrations (Klaviyo, ActiveCampaign sync) — paid credential seams own external platform sync
- SMS or push notification (email only) — those are separate paid modules with carrier relationships
- List segmentation beyond purchase history (e.g., customers in California who viewed product X) — paid owns advanced audience computation
- Personalization tokens beyond customer name/order ID — paid owns dynamic content engine
Data model
Migration required. New entities: newsletters.subscribers {id, email, firstName, lastName, subscribedAt, unsubscribedAt, isCustomer, tags[], consentLevel, hardDeleteAt}; newsletters.campaigns {id, name, templateId, recipientCount, sentAt, scheduledFor, status, openCount, clickCount, unsubscribeCount, createdBy}; newsletters.opens {id, campaignId, subscriberId, openedAt}; newsletters.templates {id, name, html, blocks[], createdAt}.
API
- POST /api/newsletters/subscribers
- GET /api/newsletters/subscribers
- DELETE /api/newsletters/subscribers/{id}
- DELETE /api/newsletters/subscribers/{id}/permanent
- POST /api/newsletters/campaigns
- GET /api/newsletters/campaigns
- GET /api/newsletters/campaigns/{id}
- POST /api/newsletters/campaigns/{id}/send
- GET /api/newsletters/templates
Every route added here must also appear in src/pages/openapi.json.ts — a test
fails the build if it does not.
Admin
Subscribers dashboard: import CSV, view list, manually add, bulk tag, delete. Campaign builder: template selector, drag-drop editor, send scheduling, preview. Analytics page: per-campaign open/click heatmap, unsubscribe trends. Template library: built-in basic templates, custom save/load.
The seam — why this is core
Core owns the interface (template builder, subscriber send, open tracking) and honest implementation. Paid modules own automation workflows (state machines), multivariate testing (statistics), advanced segmentation (business logic), third-party sync (credentials).
Core owns the interface and honest hand-modelled implementation (template builder, subscriber send). Paid owns advanced segmentation, automation workflows, and multivariate testing which require business-logic infrastructure and support commitment.
Dependencies
- Orders module (to populate isCustomer flag)
- Email transport layer (SMTP or SES)
- Scheduler (for scheduled sends)
- Settings (to store sender email, reply-to)
Acceptance checks
Each of these must be able to fail. Before claiming this is done, break the code deliberately and watch each one go red.
- A subscriber can sign up via form and receive double-opt-in confirmation email
- An unsubscribe link in any campaign email unsubscribes that subscriber and marks unsubscribedAt
- A GDPR hard-delete request removes all subscriber records and clears opens/clicks tables
- A campaign sent to 1000 subscribers shows exactly 1000 in recipientCount; open rate = opens/recipients*100
- An open is recorded once per unique subscriber per campaign (deduplication by subscriber+campaign)
- A merchant can export subscriber list to CSV with email, name, subscription date, customer status
- Template with {{unsubscribeLink}} token renders correctly in final email
- Segmentation by ‘customers only’ filters to subscribers where isCustomer=true based on orders table join
- Preview renders correctly in mobile viewport (320px) and dark mode
- A campaign scheduled for 2 hours from now sends at scheduled time within ±5 minutes
Risks
Email deliverability: if sender domain lacks SPF/DKIM/DMARC, emails land in spam. GDPR hard-delete: developers may forget to clear opens/clicks when deleting subscribers, leaking data. Subscriber deduplication: multiple signups with same email may apply updates to wrong record. Template HTML injection: user-provided HTML can cause XSS in preview. Email rate limiting: sending 100k emails in 1 second may be rejected or throttled; queue and backoff required. Database size: opens/clicks table grows by millions/month; partitioning strategy needed.
Commercial context
| Suggested price | free (core): template builder, send to subscriber list, open tracking; paid plans $25–60/mo for segmentation, automation, advanced A/B testing |
| Rival anchor | Shopify Email (free on paid plans); MailChimp ($20–50/mo); ActiveCampaign ($15+/mo) |
The anchor is what the nearest equivalent charges on Shopify or Magento today. It is context for a pricing decision, not the decision.
Generated from the commerce plan. See docs/COMMERCE-PLAN.md for the full
catalogue and ../../AI-GUIDE.md for how to work on this repository.