Email Construction Guide
Version: 2.0.0 | Last Updated: January 2026 | Status: Production
Table of Contents
1. Overview
JGPNR uses a queue-based email system powered by BullMQ for reliable, asynchronous email delivery. All transactional emails are HTML-formatted with inline styles for maximum email client compatibility.
Email System Components
| Component | Location | Purpose |
|---|---|---|
| Email Service | src/modules/email/email.service.ts | Core email logic |
| Email Queue | src/config/queue.ts | BullMQ queue configuration |
| Email Templates | src/modules/email/templates/ | HTML template files |
2. Email Architecture
Queue-Based Delivery
3. Email Templates
1. Order Confirmation Email
File: templates/orderResult.ts
Trigger: Order created successfully.
Dynamic Data
| Placeholder | Source | Description |
|---|---|---|
| ${customerName} | order.customer.firstName + lastName | Full customer name |
| ${orderNumber} | order.orderNumber | Order ID (e.g., ORD-123456) |
| ${ticketCode} | ticket.ticketCode | Ticket ID (e.g., TKT-ABC123) |
| ${validUntil} | ticket.validUntil (formatted) | Ticket expiry date |
| ${gameArenaLocation} | systemSettings.gameArenaLocation | Physical venue address |
Email Types & Triggers
All transactional emails are sent through the BullMQ queue with retry logic.
| Email Type | Trigger | Template File | Attachments |
|---|---|---|---|
| Order Confirmation | Order created (PENDING) | orderConfirmation.template.ts | None |
| Payment Confirmation | Payment verified (PAID) | paymentConfirmation.template.ts | QR Code images |
| Session Reminder (24h) | 20-28 hours before session | reminder.template.ts | None |
| Session Reminder (2h) | 1-3 hours before session | reminder.template.ts | None |
| Expiry Reminder | 1d, 3d (7d for subs) before expiry | expiryReminder.template.ts | None |
| Shipment Update | Status → SHIPPED or DELIVERED | shipmentUpdate.template.ts | None |
| Admin Campaign | Manual send from admin panel | campaign.template.ts | Optional |
| Admin Reports | Scheduled (daily/weekly/monthly) | scheduler.jobs.ts (inline) | CSV exports (monthly) |
Expiry Date Calculation
Note: The expiry date shown in emails is calculated
dynamically using ticketLifecycle.utils.ts.
- Regular tickets: Use
ticket.validUntil - Subscription tickets: Use
ticket.subscriptionExpiresAt - Date formatting: Uses Africa/Lagos timezone via
formatDateLagos()
Reminder Timing Configuration
| Setting | Field | Default | Description |
|---|---|---|---|
| 24h Window Min | reminder24HoursMin | 20 hours | Lower bound for 24h reminder |
| 24h Window Max | reminder24HoursMax | 28 hours | Upper bound for 24h reminder |
| 2h Window Min | reminder2HoursMin | 1 hour | Lower bound for 2h reminder |
| 2h Window Max | reminder2HoursMax | 3 hours | Upper bound for 2h reminder |
Error Handling
4. Dynamic Data & Placeholders
Two types of placeholders are used:
- Double-Brace ({{...}}): System settings (Business Name, Address).
- Template Literals (${...}): Runtime data (Order specs, User info).
System Settings Placeholders
| Placeholder | Source |
|---|---|
| {{businessName}} | SystemSettings.businessName |
| {{businessAddress}} | SystemSettings.businessAddress |
| {{supportEmail}} | SystemSettings.supportEmail |
| {{contactPhone}} | SystemSettings.contactPhone |
Runtime Placeholders
| Placeholder | Source |
|---|---|
| ${customerName} | order.customer.firstName |
| ${orderNumber} | order.orderNumber |
| ${ticketCode} | ticket.ticketCode |
| ${validUntil} | ticket.validUntil (formatted) |
| ${totalAmount} | order.totalAmount (formatted) |
5. Reminder Logic
Cron jobs run hourly to check for:
Session Reminders
- 24h Reminder: Sent day before session (Tuesday for Wednesday, etc.)
- 2h Reminder: Sent 2 hours before session start time
Expiry Reminders
- 7-Day Warning: Sent 7 days before ticket expires
- 3-Day Warning: Sent 3 days before ticket expires
- Final Warning: Sent 1 day before ticket expires
Note: Reminder intervals are configurable via SystemSettings in the admin panel.
6. Attachments
PDF Generation
- Ticket PDF: Generated using PDFKit with QR codes embedded
- Receipt PDF: Order summary with payment details
QR Code Attachments
- Generated using
qrcodelibrary - PNG format, inline in PDF or as separate attachments
- Contains ticket code for scanner validation
7. Styling Guidelines
Emails must be compatible with Outlook, Gmail, and Apple Mail.
- Use Tables for layout (600px max width)
- Use Inline CSS only
- Avoid Flexbox/Grid in email templates
- Use web-safe fonts with fallbacks
8. Branding Configuration
- Header: Business logo and name
- Footer: Contact info, social links, unsubscribe
- Colors: Primary brand color from SystemSettings
9. Error Handling
Failed jobs are automatically retried 3 times by BullMQ. If SMTP fails, the job remains in the failed queue for inspection.
Monitoring
- EmailLog table: All sent emails logged with status
- BullMQ Dashboard: View pending, active, failed jobs
- System Health: Email queue depth visible in /health/detailed