Background Worker Guide (apps/worker)
Deep dive into the BullMQ background delivery engine, direct MX SMTP transport, DKIM signing, and webhook worker in apps/worker.
The Background Worker (apps/worker) processes queued delivery jobs. This keeps SMTP network delays outside the API request, but throughput depends on server resources and recipient mail servers.
1. Directory Structure
apps/worker/
├── src/
│ ├── config/ # Redis and PostgreSQL connections
│ │ ├── db.ts # PrismaClient connection instance
│ │ └── env.ts # Zod-validated environment config
│ ├── workers/ # BullMQ Worker instances
│ │ ├── emailDelivery.worker.ts # Outbound SMTP direct dispatch worker
│ │ └── inboundEmail.worker.ts # Inbound email processing & webhook trigger
│ ├── services/ # Delivery execution logic
│ │ ├── mxResolver.service.ts # Recipient domain DNS MX resolution
│ │ ├── smtpTransport.service.ts# Direct MTA port 25 SMTP handshake
│ │ └── webhookDispatcher.service.ts # HMAC-signed HTTP webhook poster
│ ├── utils/ # DKIM signing & FCrDNS checks
│ │ ├── dkimSigner.ts # Nodemailer 2048-bit DKIM configuration
│ │ └── deliverabilityCheck.ts # Pre-flight PTR and EHLO verifier
│ └── index.ts # Worker service entry point & lifecycle
└── tsconfig.json2. Decoupled Delivery Architecture
Client API Request
│
▼
apps/api (Port 4000)
│ (Enqueues job)
▼
Redis BullMQ Queue ('email-delivery-queue')
│
▼
apps/worker (Concurrent Workers)
│
├─► 1. Lookup Domain & Decrypt 2048-bit RSA DKIM Private Key
├─► 2. Query Recipient Domain MX Records (e.g. gmail-smtp-in.l.google.com)
├─► 3. Connect to the recipient MX on port 25 (TLS depends on negotiation and configuration)
├─► 4. Transmit with EHLO mail.yourdomain.com & Return-Path bounces@send.<domain>
└─► 5. Update PostgreSQL status to DELIVERED or schedule BullMQ exponential retry3. Direct MX Resolution & SMTP Transport
The worker attempts direct delivery from your server to the recipient domain's mail server. This requires outbound port 25 access and correct DNS and mail-server configuration.
MX Resolution Workflow
When an outbound email job is picked up by emailDelivery.worker.ts:
- Extract recipient domain (e.g.
user@gmail.com->gmail.com). - Query DNS for
MXrecords ordered by priority:const mxRecords = await dns.promises.resolveMx(domain); const primaryMta = mxRecords.sort((a, b) => a.priority - b.priority)[0].exchange; - Initialize a direct Nodemailer SMTP transport pointing to
primaryMta:25.
2048-Bit DKIM Signing
The worker decrypts the domain's 2048-bit RSA private key using ENCRYPTION_KEY and injects cryptographic signatures into every outbound MIME envelope:
const transport = nodemailer.createTransport({
host: primaryMta,
port: 25,
secure: false,
dkim: {
domainName: domain.name,
keySelector: domain.dkimSelector || 'esp',
privateKey: decryptedPrivateKey,
},
name: env.SMTP_EHLO_HOSTNAME, // e.g. mail.yourdomain.com
});4. Inbound Email Worker & Webhooks
When incoming emails are captured by the Inbound SMTP receiver on port 2525, they are queued to inbound-email-queue:
inboundEmail.worker.tsparses headers, extracts spam indicators, and stores parsed HTML inInboundEmail.- If your account has active webhooks subscribed to
inbound.email.receivedor delivery lifecycle events (email.sent,email.delivered,email.bounced),webhookDispatcher.service.tssends an HTTP POST with anX-EmitMail-Signatureheader calculated using HMAC-SHA256:
const signature = crypto
.createHmac('sha256', webhookSecret)
.update(JSON.stringify(payload))
.digest('hex');5. Concurrency & Performance Tuning
Worker concurrency is controlled via environment variables:
# Number of parallel email delivery jobs processed per worker process
WORKER_CONCURRENCY=10When running in production under heavy volume, you can scale workers horizontally by deploying multiple instances of emitmail-worker connected to the same Redis cluster without changing the API server.
6. Testing Worker Delivery Locally
EmitMail includes dedicated simulation scripts to test the worker pipeline end-to-end:
# Test Resend SDK Queue -> Worker -> Delivery flow
pnpm test:resend-worker
# Run full deliverability and security check
pnpm test:deliverabilityBackend API Guide (apps/api)
Deep-dive architecture, database models, Express middleware, 2048-bit DKIM crypto, and Inbound SMTP receiver in apps/api.
Dashboard UI Guide (apps/dashboard)
Frontend architecture, Next.js 16 App Router, Cloudflare Kumo design system tokens, and UI standards in apps/dashboard.