Multi-company isolation is the decision that drags everything else along. The Entity → Project → Users hierarchy hangs off an authorisation service that checks, on every operation, whether the row belongs to the user's entity. Companies do not carry an entity column: they are isolated through the campaign that moves them, because the same record can appear in two campaigns with different treatment.
Sends do not go through a broker: they are queued in a table and a scheduler reviews it every second, with retry and automatic recovery of stuck sends after sixty seconds. If the process dies halfway through a campaign, the queue is still there when it starts up and the work is not duplicated.
Around that core: address validation before writing, a per-entity blocklist that cancels what is queued, one-click unsubscribes with a signed token, templates with attachments and more than fifteen variables, and periodic synchronisation of each user's mail over OAuth with the refresh tokens encrypted with AES-256-GCM in the database.
Campaign → mobilisation (no duplicates, off the blocklist)
→ send profile: window, pause, daily quota, ramp
→ table queue → worker (concurrency 5, 1 s cycle)
→ email provider → webhook: delivery · open · bounce · complaint · unsubscribe
→ single inbox with threads, assignment and status