Problem 3: Compliance Conflicts
Marketing email requires List-Unsubscribe headers (RFC 8058) and opt-out mechanisms. Transactional email doesn't. Mixing them in one queue creates compliance complexity.
Problem 4: Monitoring Complexity
Blending transactional and bulk metrics makes it impossible to know if your transactional deliverability is healthy.
Architecture: Separate MTA Stacks
Recommended Architecture for 5M+/month Senders
┌─────────────────────────────────────────────────────────┐
│ Application Layer │
│ (Orders, Auth, Marketing Platform, CRM) │
└──────────────────────┬──────────────────────────────────┘
│
┌─────────────┴──────────────┐
│ │
┌────────▼─────────┐ ┌──────────▼──────────┐
│ Transactional │ │ Bulk/Marketing │
│ SMTP Relay │ │ SMTP Relay │
│ (KumoMTA-1) │ │ (KumoMTA-2) │
│ │ │ │
│ - High priority │ │ - Normal priority │
│ - 2s SLA │ │ - 4h campaign SLA │
│ - Separate IPs │ │ - Separate IPs │
│ - P0 alerting │ │ - P1 alerting │
└────────┬─────────┘ └──────────┬──────────┘
│ │
┌────────▼─────────┐ ┌──────────▼──────────┐
│ Dedicated │ │ Dedicated │
│ IPs (warm, │ │ IPs (warm, │
│ established rep) │ │ separate rep) │
└───────────────────┘ └─────────────────────┘
Separate DKIM and Domains
Transactional:
From: noreply@mx.example.com
- DKIM:
mail._domainkey.mx.example.com
- Separate reputation for critical sending
Bulk/Marketing:
From: hello@example.com
- DKIM:
mail._domainkey.example.com
- More tolerant reputation risk
KumoMTA Configuration: Transactional vs Bulk
Transactional Configuration (High Priority)
-- /etc/kumomta/transactional.conf
-- High-priority SMTP listener
kumo.start_smtp_listener {
listen = "[::]:2525",
name = "transactional",
relay_hosts = { "10.0.0.0/8" },
auth_require_tls = true,
}
-- Prometheus metrics (separate port)
kumo.start_http_listener {
listen = "[::]:2001",
trusted_hosts = { "127.0.0.1" },
}
-- Minimal queue depth for low latency
kumo.configure_queue {
max_queue_depth = 5000,
retry_interval = "1m",
max_retry_age = "24h",
}
-- DKIM signing
kumo.configure_dkim_signing {
domain = "mx.example.com",
selector = "mail",
key_file = "/etc/kumomta/keys/mail._domainkey.mx.example.com.pem",
}
Bulk Configuration (Normal Priority)
-- /etc/kumomta/bulk.conf
-- Bulk/marketing listener
kumo.start_smtp_listener {
listen = "[::]:2526",
name = "bulk",
relay_hosts = { "10.0.0.0/8" },
auth_require_tls = true,
}
-- Prometheus metrics (separate port)
kumo.start_http_listener {
listen = "[::]:2002",
trusted_hosts = { "127.0.0.1" },
}
-- Higher queue depth for volume
kumo.configure_queue {
max_queue_depth = 100000,
retry_interval = "5m",
max_retry_age = "72h",
}
-- DKIM signing
kumo.configure_dkim_signing {
domain = "example.com",
selector = "mail",
key_file = "/etc/kumomta/keys/mail._domainkey.example.com.pem",
}
-- RFC 8058 List-Unsubscribe headers
kumo.on("smtp_message_received", function(domain, meta)
local headers = meta.headers or {}
-- Only add for bulk campaigns
if headers["X-Campaign-Type"] == "marketing" then
kumo.add_header("List-Unsubscribe",
"<mailto:unsubscribe@example.com?subject=unsubscribe>")
kumo.add_header("List-Unsubscribe-Post",
"List-Unsubscribe=One-Click")
kumo.add_header("Precedence", "bulk")
end
end)
Compliance: CAN-SPAM and GDPR
Transactional Exemption
Key fact: CAN-SPAM exempts transactional emails from:**
- Physical postal address requirements
- Opt-out link requirements (though still recommended)
Transactional exemption applies when:
- Email is to facilitate an existing transaction
- Email is about a purchase or account status
- Email is a one-to-one communication
Marketing emails are NOT exempt:
- Newsletters, promotions, announcements
- Re-engagement campaigns
- Non-triggered educational content
GDPR Considerations
| Email Type |
Consent Required |
Legitimate Interest |
| Transactional |
No (contractual necessity) |
N/A |
| Marketing (explicit opt-in) |
Yes |
No |
| Marketing (existing customer) |
Yes (soft opt-in in some EU countries) |
Sometimes |
| Re-engagement |
Yes |
No |
For bulk sending to EU residents:
- Explicit consent required before sending
- Double opt-in recommended
- Clear unsubscribe mechanism
- Data minimization (don't retain more than needed)
When NOT to Separate
Separating transactional and bulk infrastructure adds operational complexity. Don't separate if:
- Your total volume is under 500K/month
- Your transactional volume is under 10K/month
- You have no engineering capacity to manage two stacks
- Your marketing and transactional emails come from the same product (e.g., a marketplace where order confirmations ARE your marketing)
In these cases, use a single MTA with traffic shaping to prioritize transactional:
kumo.on("smtp_message_received", function(domain, meta)
local headers = meta.headers or {}
if headers["X-Priority"] == "high" then
kumo.set_queue_priority("high")
end
end)
Monitoring: Separate Metrics for Each
Transactional Metrics Dashboard
| Metric |
Target |
Alert |
| Delivery success rate |
> 99.9% |
< 99.5% |
| End-to-end latency (p95) |
< 30s |
> 60s |
| Queue depth |
< 100 |
> 500 |
| Hard bounce rate |
< 0.1% |
> 0.5% |
| 5xx error rate |
< 0.1% |
> 0.5% |
Bulk Campaign Metrics Dashboard
| Metric |
Target |
Alert |
| Campaign delivery rate |
> 96% |
< 93% |
| Campaign completion time |
< 4 hours |
> 8 hours |
| Hard bounce rate |
< 2% |
> 5% |
| Soft bounce rate |
< 5% |
> 10% |
| Complaint rate |
< 0.1% |
> 0.3% |
| Unsubscribe processing |
< 10 days |
> 10 days |
FAQ
Q: Can I use the same domain for transactional and bulk email?
A: Technically yes, but not recommended. If your bulk sending damages the domain's reputation, your transactional emails suffer too. Use subdomains (e.g., mx.example.com for transactional, example.com for bulk).
Q: Should I use separate IP addresses for transactional and bulk?
A: Yes — always. This is the most effective way to prevent reputation cross-contamination. Your transactional IP should have established, pristine reputation. Your bulk IP(s) can absorb more risk.
Q: Can I send transactional and bulk through the same KumoMTA instance?
A: Yes, using Lua policies to route and prioritize differently. But for high-volume operations (10M+/month), separate instances on separate infrastructure provide better isolation.
Q: Does SendGrid/Mailgun separate transactional and bulk?
A: Yes — both have separate APIs and infrastructure for transactional (via SMTP/API) and marketing (via marketing campaigns). This is one reason enterprise senders often migrate to self-hosted KumoMTA for full control.
Q: What's the minimum volume where separation becomes worth it?
A: When your bulk campaigns regularly exceed 100K emails/session, or when transactional SLA < 30s is business-critical. For most organizations, this is around 2-5M total monthly volume.
Get Help With Email Architecture
PostMTA designs email infrastructure for high-volume senders:
- Transactional/bulk separation architecture
- KumoMTA multi-stack configuration
- Compliance audit (CAN-SPAM, GDPR)
- Reputation management and IP strategy
👉 Talk to our infrastructure team →
For related guides, see SMTP Relay Setup Guide, IP Warmup Strategies, and KumoMTA Setup Guide.
References: RFC 8058 (List-Unsubscribe) | CAN-SPAM Requirements