DarDev warms outbound mail on a single sender identity—news@send.dardev.net—toward roughly ten thousand messages per month (about three hundred thirty per day) using MAIL_SEND_PROFILE=warmup, Stalwart throttles, and paced sync-worker jobs. New IPs and subdomains do not get one-shot blasts to imported CRM lists; they earn reputation with consistent volume, low complaints, and aligned SPF, DKIM, and DMARC.
Warm-up discipline appears in our MAIL-RULES team guide and hybrid sender roadmap M0 baseline. This article explains how operators scale without burning send.dardev.net. Pair it with why-send-dardev-subdomain for DNS isolation and inside-unified-mailer-stack for where throttles sit in compose.
Why one sender during warm-up
Mailbox providers score domains, IPs, and From identities together. Splitting warm-up across noreply@, marketing@, and alerts@ on the same young subdomain dilutes signal and makes bounce handling harder. DarDev standardizes on news@send.dardev.net for company digest, sync-worker drips, and paced campaign jobs until MAIL_SEND_PROFILE=scale is explicitly approved.
Product-specific subdomains—sales.dardev.net for 20.tn outreach, agents.dardev.net for automation—carry their own SPF and reputation curves. Company warm-up rules still apply: do not point Listmonk at Zoho root addresses, and do not disable throttles because a launch date moved up.
MAIL_SEND_PROFILE=warmup
Environment variable MAIL_SEND_PROFILE selects rate helpers in sync-worker mail-rate.js. warmup applies conservative MAIL_SEND_DELAY_MS between submissions and coordinates with Stalwart dardev-warmup-* throttle rules loaded from stalwart/production/warmup.ndjson. scale relaxes delays after ops reviews DMARC aggregate reports, bounce rates, and seed inbox placement.
.env.example documents both profiles. configure-production.sh on dardev-vps applies Listmonk performance caps—app.concurrency 3, max_conns 3, message_rate 1—so the UI cannot accidentally outrun Stalwart even when an operator triggers a manual campaign during warm-up.
Stalwart throttle numbers (M0 baseline)
- Global outbound cap near 450 messages per day during initial warm-up window
- Per recipient domain cap near 50 messages per hour to avoid tripping provider velocity filters
- Queue retention so bursts from sync-worker jobs smooth into SMTP submission
- Bounce and complaint visibility in mta.dardev.net admin before raising limits
Throttles are infrastructure truth—tuning warmup.ndjson and re-applying beats commenting out limits in application code. If a test list needs faster delivery, shrink the list or extend the job window; do not bypass Stalwart on a shared production IP.
Drip jobs vs one-shot blasts
Hybrid sender M3 campaign jobs accept listId, subject, html, optional rate, and dryRun. A hundred-recipient test list should complete over a configurable window with progress polling on GET /api/mail/campaign/:jobId. Operators watch sent versus total; cancelling a job stops SMTP without deleting Listmonk subscribers.
Daily digest via DAILY_SEND_MODE=direct is the smallest live send: roughly ten staff on internal:staff, From news@send.dardev.net, cron 08:00 Africa/Tunis. It exercises SMTP auth, template rendering, and throttle paths daily without marketing volume.
Cold CRM imports—schools, accountants, SMB prospects—never enter this warm-up path on import day. Twenty holds consentEmail UNKNOWN until subscribe or documented opt-in. Violating that risks compliance issues and spikes complaint rates that undo weeks of warm-up.
Monitoring during warm-up
- DMARC aggregate reports
rua=mailto:dmarc@dardev.net on _dmarc.send surfaces alignment failures and unexpected sources.
- Stalwart bounce log
Hard bounces trigger list hygiene review before the next batch.
- Seed inboxes
Gmail and Microsoft personal test accounts for placement checks after DNS or template changes.
- Milestone scripts
wsl bash scripts/mail/test-milestone.sh M0 after throttle edits; validate-mail-stack.sh before scale profile.
- Listmonk hygiene
Separate product lists; remove chronic hard bounces; never merge cold imports for volume padding.
Scaling path to production volume
Target steady state for DarDev company mail is about ten thousand messages per month on news@send.dardev.net—newsletter, digest, and paced product updates combined. Reaching that level is incremental: raise Stalwart caps in warmup.ndjson, switch MAIL_SEND_PROFILE toward scale, and expand opted-in list segments only when bounce and complaint rates stay flat week over week.
Hesabi and other product domains may use send.hesabi.tn with their own warm-up curve per manifest mail.fromDomain. Do not borrow DarDev company throttle headroom for product launches without a separate subdomain and DNS package.
Self-hosted operators weigh control versus operational burden in self-hosted-email-vs-saas. Warm-up is the recurring cost of owning the IP: no shared pool to hide behind, but also no neighbor sender poisoning your domain.
Rollback when warm-up goes wrong
If complaint rates spike, pause sync-worker campaign jobs first, then Listmonk UI campaigns on the same subdomain. Lower warmup.ndjson caps before investigating template or list content. Recovering reputation takes longer than tightening throttles—document the incident in runbooks and re-seed inboxes before resuming prior volume.
What is the daily send target during warm-up?
Roughly 333 messages per day toward 10k per month on news@send.dardev.net, enforced by MAIL_SEND_PROFILE=warmup and Stalwart throttles—not a hard guarantee if queues back up.
Can Listmonk send faster than sync-worker?
Listmonk UI campaigns share the same Stalwart egress and throttles. UI concurrency is capped at 3/3/1 during warm-up. Speed limits are MTA-side.
When do we switch to MAIL_SEND_PROFILE=scale?
After M4 sign-off criteria: stable DMARC reports, acceptable bounce rate, seed placement, and explicit ops approval documented in runbooks.
Does warm-up apply to sales.dardev.net?
Yes for new subdomains. Each outbound domain needs its own reputation curve even on the same VPS IP.
What if a campaign must go out today?
Send only to fully opted-in segments that fit today's throttle budget, or pause and reschedule as a multi-day worker job. Do not disable throttles or import cold CRM rows.



