120 lines
4 KiB
Markdown
120 lines
4 KiB
Markdown
# Primary & Satellite Topology
|
||
|
||
## Core principle
|
||
|
||
**Primaries** are the mailboxes whose reputation matters for cold outreach.
|
||
**Satellites** exist only to generate realistic, controlled engagement with primaries.
|
||
|
||
```
|
||
┌─────────────────┐
|
||
│ Primary │
|
||
│ hello@fillcare │
|
||
└────────┬────────┘
|
||
│
|
||
┌───────────────────┼───────────────────┐
|
||
│ │ │
|
||
┌────▼────┐ ┌────▼────┐ ┌────▼────┐
|
||
│Satellite│ │Satellite│ │Satellite│
|
||
│ Gmail 1 │ │ Yahoo │ │ Live │
|
||
└─────────┘ └─────────┘ └─────────┘
|
||
```
|
||
|
||
## Traffic rules
|
||
|
||
| Direction | Allowed | Notes |
|
||
|-----------|---------|-------|
|
||
| Satellite → Primary | Yes | Main warmup send |
|
||
| Primary → Satellite | Yes | Reply to satellite (completes thread) |
|
||
| Satellite → Satellite | No | Wastes quota; looks unnatural |
|
||
| Primary → Primary | No | Never warm primaries against each other |
|
||
| Satellite → unrelated external | No | Only campaign-assigned primaries |
|
||
|
||
## Multi-primary support
|
||
|
||
One operator can run **N campaigns** concurrently:
|
||
|
||
```
|
||
Campaign A: primary=hello@fillcareapp.com ← satellites [gmail1, yahoo1, live1]
|
||
Campaign B: primary=sales@otherdomain.com ← satellites [gmail2, yahoo2]
|
||
```
|
||
|
||
Satellites may be **shared** across campaigns only if explicitly enabled (default: dedicated per primary to avoid cross-brand leakage).
|
||
|
||
## FillCare example setup
|
||
|
||
| Mailbox | Role | Provider |
|
||
|---------|------|----------|
|
||
| hello@fillcareapp.com | Primary | Google Workspace |
|
||
| personal@gmail.com | Satellite | Gmail |
|
||
| personal@yahoo.com | Satellite | Yahoo |
|
||
| personal@live.com | Satellite | Outlook |
|
||
| (+ 1–2 more) | Satellite | Mixed |
|
||
|
||
### Minimum viable pool
|
||
|
||
- 1 primary + **2 satellites** (technical minimum)
|
||
- Recommended: 1 primary + **4–6 satellites** for natural variety and reply distribution
|
||
|
||
## Satellite lifecycle
|
||
|
||
```mermaid
|
||
stateDiagram-v2
|
||
[*] --> Unassigned: Add mailbox
|
||
Unassigned --> Active: Assign to campaign
|
||
Active --> Paused: Operator pause
|
||
Paused --> Active: Resume
|
||
Active --> Error: Auth/IMAP failure
|
||
Error --> Active: Fix + test
|
||
Active --> Unassigned: Remove from campaign
|
||
```
|
||
|
||
## Add / remove operations
|
||
|
||
### Add satellite
|
||
|
||
1. `POST /mailboxes` with `role: satellite`
|
||
2. Test SMTP/IMAP
|
||
3. `POST /campaigns/:id/satellites` to assign
|
||
|
||
### Remove satellite
|
||
|
||
1. `DELETE /campaigns/:id/satellites/:mailboxId` — stops new sends
|
||
2. In-flight threads complete or timeout
|
||
3. Optional: `DELETE /mailboxes/:id` if fully removed
|
||
|
||
### Add primary
|
||
|
||
1. `POST /mailboxes` with `role: primary`
|
||
2. `POST /campaigns` with recipe + bounds
|
||
3. Assign satellites
|
||
4. Start campaign (`status: active`)
|
||
|
||
## Peer network (phase 3 — optional)
|
||
|
||
When enabled, additional engagement from vetted peer mailboxes:
|
||
|
||
| Aspect | Own satellites | Peer network |
|
||
|--------|----------------|--------------|
|
||
| Control | Full | Limited |
|
||
| ESP risk | Lower | Higher (pool quality) |
|
||
| Cost | User supplies accounts | Platform fee |
|
||
| Detection | User responsible | Platform must maintain pool health |
|
||
|
||
**Recommendation:** Ship own-satellite-only first. Peer network requires bounce monitoring, DNS validation, and pool rotation — significant ops burden.
|
||
|
||
## Dispatcher pairing (target logic)
|
||
|
||
```
|
||
for each campaign where status=active:
|
||
if today.sends < schedule.plannedSends:
|
||
satellite = pickWeighted(campaign.satellites)
|
||
primary = campaign.primaryMailbox
|
||
queueSend(from=satellite, to=primary)
|
||
```
|
||
|
||
Reply path (rescuer):
|
||
|
||
```
|
||
if shouldReply(campaign.replyRatePercent):
|
||
reply(from=primary, to=satellite, inReplyTo=original)
|
||
```
|