Sending 1 Million Emails in 25 Minutes
High-Performance Mautic on AWS
About the Project
This sits inside a larger multi-tenant SaaS platform, where each tenant runs a white-labeled Mautic instance. As volume grew, the default pipeline — emails sent one by one via SMTP — became a bottleneck. Campaigns with hundreds of thousands of recipients took hours or timed out. We had to rebuild sending from scratch.
- Context
- Multi-tenant white-label Mautic
- Bottleneck
- One-by-one SMTP sending
- Target
- 1M personalized emails in 25 min
Performance Results
The Challenge
A production-scale pipeline had to solve volume, personalization, deliverability, and cost at the same time.
Send 1M+ emails in under 30 minutes
Personalize dynamic content per recipient
Keep deliverability at high volume
Work around AWS SQS 256KB message limits
Route bounces across multiple tenants
Run cost-efficiently on spot instances
The Solution
We replaced Mautic's default one-by-one SMTP sending with a three-stage parallel pipeline designed for throughput.
- Architecture
- Three-stage parallel pipeline
- Workers
- 52 pods assembling payloads
- Dispatch
- Mailgun batch API, 1,000 per call
Segment Scanning
Mautic scans the campaign segment and batches millions of contacts into queue messages. This stage completes in milliseconds to seconds regardless of segment size, thanks to optimized database queries that only extract contact IDs.
Payload Assembly
52 parallel worker pods consume messages from the queue. Each worker assembles the full email payload: resolving dynamic content, personalizing templates per recipient, and batching up to 1,000 recipients per Mailgun API call.
Mailgun Batch API
Assembled batches are dispatched to Mailgun's batch API endpoint. Each API call handles up to 1,000 recipients with per-recipient variable substitution, eliminating the need for individual SMTP connections.
Engineering Challenges
Volume was the brief. These are the constraints that actually shaped the pipeline.
01 Custom SQS + S3 Transport
AWS SQS has a 256KB message size limit. Email payloads with personalized HTML content easily exceed this. We built a custom transport layer: the full payload is stored in S3, and the SQS message contains only a reference to the S3 object. Workers fetch the payload from S3 on consumption. This eliminates the size constraint while maintaining queue reliability.
02 Intelligent Bounce Handling
With hundreds of tenants sharing a Mailgun domain, bounce notifications needed routing to the correct tenant instance. We implemented a custom header injection system: each outgoing email carries a tenant identifier header. A polling-based bounce processor reads Mailgun's event stream, extracts the tenant ID, and routes the bounce to the correct Mautic instance for contact status updates.
03 Graceful Processing Under Spot Interruptions
Worker pods run on spot instances for cost savings, but AWS can reclaim these with 2 minutes notice. We implemented graceful shutdown handling: when a termination signal arrives, workers stop consuming new messages, finish processing their current batch, and write checkpoints. A force-kill fallback ensures no orphaned processes. Messages from interrupted workers return to the queue automatically.
04 Email Deduplication & Queue Priority
With 52 parallel workers and thousands of queue messages, preventing duplicate sends is critical. We implemented a Redis-based deduplication layer that tracks processed contact IDs across all workers in real-time. Queue priority ensures time-sensitive campaigns are processed before bulk sends.
1,000,000
Emails in 25 minutes
40,000
Emails per minute
52
Parallel workers
0
Emails lost
Business Impact
| # | Outcome | What changed |
|---|---|---|
| 01 | Cost | Lower infrastructure cost than projected, thanks to spot instances. |
| 02 | Deliverability | API-based sending with reputation management kept inbox placement intact. |
| 03 | Reliability | Zero email loss during spot interruptions. |
| 04 | Reuse | SQS + S3 transport pattern reusable across the platform. |
| 05 | Scale | Ready for 300–500 tenants sending at once. |
Tech Stack
| Layer | Tools |
|---|---|
| Email Delivery | Mailgun Batch API |
| Queue | AWS SQS S3 transport |
| Application | PHP Symfony Mautic |
| Storage | S3 FSx for Lustre |
| Orchestration | Kubernetes (EKS) Karpenter |
| Infrastructure | Spot instances Terraform |
| Monitoring | Grafana Prometheus Loki |
Have a Similar Challenge?
Let's discuss your project. Free 30-minute consultation with a Mautic expert.
Talk to an Expert