4.3 KiB
Waitlist Email Sequence — Implementation Guide
Overview
This document describes how to integrate the waitlist email templates into the waitlist signup flow. The 4-email welcome sequence is designed for new ShieldAI waitlist signups.
Templates Added
| # | Template ID | Timing | Purpose |
|---|---|---|---|
| 1 | waitlist_confirmation |
Immediate | Confirm waitlist signup, show position |
| 2 | waitlist_intro |
Day +1 | Introduce ShieldAI and the problem it solves |
| 3 | waitlist_features |
Day +3 | Deep dive into product features |
| 4 | waitlist_launch_teaser |
Day +7 | Launch teaser, early adopter perks |
File: packages/shared-notifications/src/templates/default-templates.ts
- All 4 templates use
buildEmailHtml()fromwaitlist-email-layout.tsfor consistent dark-themed, responsive HTML email rendering with the ShieldAI brand (Inter font, #0a0f1e dark background, #3b82f6→#06b6d4 gradient accent). - Spanish locale (
es) is provided for template 1.
Variables per Template
waitlist_confirmation
| Variable | Type | Required | Default |
|---|---|---|---|
name |
string | no | "there" |
position |
string | yes | — |
unsubscribe_url |
string | no | https://shieldai.com/unsubscribe |
waitlist_intro
| Variable | Type | Required | Default |
|---|---|---|---|
name |
string | no | "there" |
unsubscribe_url |
string | no | https://shieldai.com/unsubscribe |
waitlist_features
| Variable | Type | Required | Default |
|---|---|---|---|
name |
string | no | "there" |
unsubscribe_url |
string | no | https://shieldai.com/unsubscribe |
waitlist_launch_teaser
| Variable | Type | Required | Default |
|---|---|---|---|
name |
string | no | "there" |
referral_url |
string | no | https://shieldai.com/waitlist |
unsubscribe_url |
string | no | https://shieldai.com/unsubscribe |
Integration Points
1. Immediate Email (on signup)
In packages/api/src/routes/waitlist.routes.ts, after prisma.waitlistEntry.create() succeeds:
import { EmailService } from '@shieldai/shared-notifications';
// Send confirmation immediately
await EmailService.getInstance().sendWithTemplate(email, {
templateId: 'waitlist_confirmation',
locale: 'en', // derive from request if available
variables: {
name: body.name || 'there',
position: String(waitlistCount),
},
});
2. Scheduled Emails (Day 1, 3, 7)
Use a job queue (BullMQ is already planned) to schedule the subsequent emails:
// On signup, enqueue 3 scheduled jobs
await emailQueue.add('send-waitlist-email', {
email: body.email,
name: body.name,
templateId: 'waitlist_intro',
}, { delay: 24 * 60 * 60 * 1000 }); // +1 day
await emailQueue.add('send-waitlist-email', {
email: body.email,
name: body.name,
templateId: 'waitlist_features',
}, { delay: 3 * 24 * 60 * 60 * 1000 }); // +3 days
await emailQueue.add('send-waitlist-email', {
email: body.email,
name: body.name,
templateId: 'waitlist_launch_teaser',
}, { delay: 7 * 24 * 60 * 60 * 1000 }); // +7 days
If BullMQ is not yet available, use setTimeout or a simple cron-based approach:
// packages/api/src/jobs/waitlist-emails.ts
// Run on a cron every hour, check for pending scheduled emails
// Store scheduled_at in WaitlistEntry metadata or a separate table
3. Rate Limiting
The EmailService already enforces a default rate limit of 60 emails/minute per recipient. No additional rate limit config should be needed for the waitlist flow.
4. Unsubscribe Handling
The email footer includes an {{unsubscribe_url}} variable. Implement a standard unsubscribe endpoint:
GET /api/unsubscribe?token=<token>— one-click unsubscribe- Store unsubscribe preferences per email address
Testing
- Unit test: Verify template rendering with
TemplateService.getInstance().resolveTemplate() - Integration test: Call
POST /api/waitlist/signupand verify email is sent (use Resend test API keys) - Manual test: Use Resend email preview to verify rendering across Gmail, Outlook, Apple Mail
Rollout Checklist
- Add
RESEND_API_KEYto production environment - Verify templates render correctly via Resend API
- Test unsubscribe flow
- Verify rate limits for launch-day traffic spike
- Monitor email delivery (bounce rate, open rate) post-launch