Most welcome email systems follow a predictable pattern: subscribe, receive three generic emails, then join a newsletter.
I think we can build something more useful without introducing an expensive automation platform.
Consider an application with 400 newsletter subscribers. Some are beginners, while others already understand your product. Sending identical onboarding messages to both groups wastes an opportunity to personalize communication.
Here's how I would design a lightweight, event-driven welcome sequence with three branches, five possible emails, and a few simple tags.
1. Model Subscribers With Minimal State
I would start with three tags:
beginnerexperiencedunengaged
Each subscriber also needs signup time, email preferences, and consent information.
const subscriber = {
id: "user_123",
email: "user@example.com",
tags: [],
subscribedAt: new Date().toISOString(),
consent: true,
unsubscribed: false
};
For production, I would persist this information in a database rather than storing it in memory.
2. Email 1: Capture Intent Immediately
My first email delivers whatever someone requested during signup.
Below download link, I would include two options:
- I'm just starting out.
- I've been doing this a while.
Each link points to an authenticated preference endpoint.
For example:
GET /preferences?choice=beginner&token=...
GET /preferences?choice=experienced&token=...
One important detail: email security scanners sometimes follow links automatically.
I would therefore show a confirmation page before permanently updating preferences. Tokens must be signed, scoped, and expire after a reasonable period.
Actual preference changes should use a validated POST request.
3. Implement Three Branches
Once preference selection is confirmed, subscriber state determines upcoming emails.
function getWelcomeSchedule(segment) {
const common = [
{ day: 0, template: "welcome" },
{ day: 8, template: "expectations" },
{ day: 12, template: "next-step" }
];
const branches = {
beginner: [
{ day: 2, template: "beginner-mistakes" },
{ day: 5, template: "beginner-checklist" }
],
experienced: [
{ day: 2, template: "advanced-tactics" },
{ day: 5, template: "campaign-teardown" }
],
unengaged: [
{ day: 3, template: "preference-reminder" },
{ day: 5, template: "general-example" }
]
};
return [...common, ...branches[segment]]
.sort((a, b) => a.day - b.day);
}
This function returns five scheduled messages for any supported segment.
I would initially classify subscribers without a preference as unselected, using unengaged only after a defined inactivity period.
4. Schedule Emails Reliably
For a small application, a queue worker or scheduled job is sufficient.
Every scheduled message should have a unique key:
const jobKey =
`${subscriber.id}:${templateId}`;
Before sending, I would check:
- Has this message already been sent?
- Is subscriber consent still valid?
- Has someone unsubscribed or reduced frequency?
- Has their preferred segment changed?
A database-backed uniqueness constraint and transactional job claiming can prevent duplicate sends across workers.
I would also suppress outdated branch messages whenever preferences change.
5. Measure Actual Engagement
Open tracking is increasingly unreliable because of privacy protections and automated activity.
I prefer measuring confirmed preference selections, meaningful clicks, replies, and unsubscribes.
Consider a hypothetical 400-subscriber cohort:
| Segment | Subscribers |
|---|---|
| Beginner | 120 |
| Experienced | 80 |
| No selection | 200 |
Initial preference selection:
(120 + 80) / 400 * 100 = 50%
If another 20 subscribers choose a preference after receiving a reminder:
220 / 400 * 100 = 55%
That's a five-percentage-point increase in known preferences, not proof of improved revenue or retention.
For accurate reporting, I would exclude detected bot activity and track each cohort separately.
6. Avoid Overengineering
Small mailing lists rarely need complex customer-data infrastructure.
Before selecting an email service provider, I would evaluate automation support, API limits, webhook reliability, and pricing.
For additional platform context, Sprout24 maintains an independent email marketing software comparison directory.
I would also implement unsubscribe handling, bounce processing, retry limits, suppression lists, and relevant email authentication requirements before going live.
Final Thoughts
My preferred architecture is straightforward:
Signup → Welcome Email → Preference Selection → Branch Scheduling → Engagement Measurement
No complicated scoring engine is necessary.
I'd start with explicit user preferences, add behavior-based segmentation only when useful, and improve implementation using real subscriber feedback.
How would you handle preference changes while multiple email jobs are already queued?
Id be interested in comparing approaches using database jobs, queue workers, or serverless functions.
Top comments (0)