Skip to content

Email Service

The LuxMart Email Service is a standalone microservice responsible for handling all email operations with features like queuing, retries, rate limiting, and multi-language templates.

Overview

The email service is a separate Go application that processes email requests from the main API via Redis queue. It provides reliable email delivery with automatic retries, priority handling, and HTML templates.

Architecture

┌─────────────┐        ┌─────────┐        ┌───────────────┐
│  Main API   │ ─────> │  Redis  │ ─────> │ Email Service │
│  (Backend)  │ Enqueue│  Queue  │ Dequeue│   (Workers)   │
└─────────────┘        └─────────┘        └───────────────┘
                                                   v
                                           ┌──────────────┐
                                           │ SMTP Server  │
                                           │  (mail.ru)   │
                                           └──────────────┘

Features

1. Redis Queue System

  • Priority-based email processing
  • Delayed retry mechanism with exponential backoff
  • Dead-letter queue for failed emails
  • Queue statistics and monitoring

2. Worker Pool

  • Configurable number of concurrent workers
  • Parallel email processing
  • Automatic template rendering
  • Error handling and retry logic

3. Rate Limiting

  • Token bucket algorithm
  • Configurable emails per minute
  • Prevents SMTP server throttling

4. Template System

  • HTML email templates
  • Multi-language support (en, ru, az, tr)
  • Embedded template files
  • Dynamic data rendering

5. Retry Mechanism

  • Automatic retry for failed sends
  • Exponential backoff (1s, 2s, 4s, up to 5min)
  • Configurable max retry attempts
  • Dead-letter queue for permanent failures

Email Types

OTP (One-Time Password)

Used for account verification, password reset, etc.

Template Files: - otp-en.html - English - otp-az.html - Azerbaijani - otp-es.html - Spanish - otp-de.html - German

Template Data:

{
  "OTP": "123456",
  "Message": "Use this code to verify your account",
  "ExpiryMinutes": 10
}

General Email

Standard HTML or plain text emails.

Priority Levels: - 10 (PriorityHigh) - High (processed first) - 5 (PriorityNormal) - Normal (default) - 0 (PriorityLow) - Low

Email Type Constants: - email.EmailTypeOTP - One-time password emails - email.EmailTypePasswordReset - Password reset emails - email.EmailTypeWelcome - Welcome/onboarding emails - email.EmailTypeOrderConfirm - Order confirmation emails - email.EmailTypeNotification - General notification emails - email.EmailTypeMarketing - Marketing/newsletter emails

Integration with Main API

The main API uses the email client to send emails via Redis queue:

Sending OTP Email

import "luxmart/backend/email"

// In your controller
emailClient := email.NewClient()
err := emailClient.SendOTPEmail(
    "user@example.com",          // to
    "Verify Your Account",       // subject
    "123456",                    // otp
    "Welcome! Verify your email", // message
    "en",                        // language
)

Sending HTML Email

emailClient := email.NewClient()
err := emailClient.SendHTMLEmail(
    []string{"user@example.com"},
    "Welcome to LuxMart",
    "<h1>Welcome!</h1><p>Thanks for joining us.</p>",
    email.EmailTypeWelcome,
    email.PriorityNormal,
)

Sending Plain Text Email

emailClient := email.NewClient()
err := emailClient.SendPlainEmail(
    []string{"user@example.com"},
    "Order Confirmation",
    "Your order #12345 has been confirmed.",
    email.EmailTypeOrderConfirm,
)

Sending Bulk Emails

recipients := []string{
    "user1@example.com",
    "user2@example.com",
    "user3@example.com",
}

emailClient := email.NewClient()
err := emailClient.SendBulkEmail(
    recipients,
    "Newsletter",
    "<h2>Monthly Newsletter</h2><p>Check out our latest products!</p>",
    true, // isHTML
    email.EmailTypeMarketing,
)

if err != nil {
    log.Printf("Failed to send bulk email: %v", err)
}

Email Client API

Client Structure

type Client struct {
    redis *redis.Client
}

func NewClient() *Client

Methods

SendOTPEmail

func (c *Client) SendOTPEmail(
    to string,
    subject string,
    otp string,
    message string,
    language string,
) error

Sends an OTP email using the appropriate language template.

Parameters: - to: Recipient email address - subject: Email subject - otp: The OTP code - message: Additional message text - language: Language code (en/az/es/de)

Supported Languages: - en, english → English (default) - az, azerbaijani → Azerbaijani - es, spanish → Spanish - de, german → German

SendHTMLEmail

func (c *Client) SendHTMLEmail(
    to []string,
    subject string,
    body string,
    emailType EmailType,
    priority EmailPriority,
) error

Sends an HTML email.

SendPlainEmail

func (c *Client) SendPlainEmail(
    to []string,
    subject string,
    body string,
    emailType EmailType,
) error

Sends a plain text email. Priority is automatically set to PriorityNormal.

SendBulkEmail

func (c *Client) SendBulkEmail(
    recipients []string,
    subject string,
    body string,
    isHTML bool,
    emailType EmailType,
) error

Sends emails to multiple recipients. Priority is automatically set to PriorityNormal. Errors for individual recipients are logged but do not stop the process.

Configuration

Environment Variables

SMTP Settings:

SMTP_HOST=smtp.mail.ru
SMTP_PORT=587
SMTPMAIL=noreply@luxmart.site
SMTPPASSWORD=your_smtp_password
SMTP_FROM=no-reply@luxmart.site

Redis Settings:

REDIS_ADDR=localhost:6379
REDIS_PASSWORD=
REDIS_DB=0

Email Service Settings:

EMAIL_MAX_RETRIES=3
EMAIL_WORKER_COUNT=5
EMAIL_RATE_LIMIT=60

Configuration Reference

Variable Default Description
SMTP_HOST smtp.mail.ru SMTP server hostname
SMTP_PORT 587 SMTP server port (use 587 for TLS)
SMTPMAIL - SMTP username/email
SMTPPASSWORD - SMTP password
SMTP_FROM no-reply@luxmart.site From email address
REDIS_ADDR localhost:6379 Redis server address
REDIS_PASSWORD - Redis password (optional)
REDIS_DB 0 Redis database number
EMAIL_MAX_RETRIES 3 Maximum retry attempts
EMAIL_WORKER_COUNT 5 Number of worker goroutines
EMAIL_RATE_LIMIT 60 Max emails per minute

Queue Management

Queue Names

  • Main Queue: email:queue
  • Delayed Queue: email:queue:delayed
  • Dead Letter Queue: email:queue:dlq

Queue Operations

Enqueue Email

email := &models.Email{
    ID:          uuid.New().String(),
    To:          []string{"user@example.com"},
    Subject:     "Test Email",
    Body:        "<h1>Test</h1>",
    IsHTML:      true,
    Priority:    models.PriorityNormal,
    MaxRetries:  3,
    RetryCount:  0,
}

queue.Enqueue(email)

Process Delayed Emails

Automatically moves delayed emails back to main queue when ready:

queue.ProcessDelayed()

Get Queue Statistics

stats, err := queue.GetStats()
// Returns queued, processing, sent, failed counts

Retry Logic

Retry Flow

  1. Email fails to send
  2. RetryCount is incremented
  3. If RetryCount < MaxRetries:
  4. Calculate exponential backoff delay
  5. Move to delayed queue
  6. If RetryCount >= MaxRetries:
  7. Move to dead-letter queue

Exponential Backoff

Retry 1: 1 second
Retry 2: 2 seconds
Retry 3: 4 seconds
Retry 4: 8 seconds (capped at 5 minutes)

Dead Letter Queue (DLQ)

Permanently failed emails are moved to the DLQ for manual inspection:

# View dead letters in Redis
redis-cli ZRANGE email:queue:dlq 0 -1

Monitoring

Service Logs

The email service provides detailed logging:

[Worker 1] Processing email ID: abc-123, To: [user@example.com], Subject: Welcome
[Worker 1] Successfully sent email ID: abc-123
[Worker 2] Failed to send email ID: def-456: connection timeout
[Worker 2] Requeued email ID: def-456 (retry 1/3)

Queue Statistics

Monitor queue health via Redis:

# Check queue size
redis-cli ZCARD email:queue

# Check delayed queue
redis-cli ZCARD email:queue:delayed

# Check dead letter queue
redis-cli ZCARD email:queue:dlq

# Get stats
redis-cli GET email:stats:queued
redis-cli GET email:stats:sent
redis-cli GET email:stats:failed

Deployment

Docker Compose (Development)

email-service:
  build:
    context: ./services/email-service
    dockerfile: Dockerfile.dev
  environment:
    SMTP_HOST: smtp.mail.ru
    SMTP_PORT: 587
    SMTPMAIL: ${SMTPMAIL}
    SMTPPASSWORD: ${SMTPPASSWORD}
    SMTP_FROM: no-reply@luxmart.site
    REDIS_ADDR: redis:6379
    EMAIL_MAX_RETRIES: 3
    EMAIL_WORKER_COUNT: 5
    EMAIL_RATE_LIMIT: 60
  depends_on:
    - redis

Docker Compose (Production)

email-service:
  image: luxmart-email-service:latest
  environment:
    SMTP_HOST: smtp.mail.ru
    SMTP_PORT: 587
    SMTPMAIL: ${SMTPMAIL}
    SMTPPASSWORD: ${SMTPPASSWORD}
    SMTP_FROM: no-reply@luxmart.site
    REDIS_ADDR: redis:6379
    EMAIL_MAX_RETRIES: 3
    EMAIL_WORKER_COUNT: 10
    EMAIL_RATE_LIMIT: 100
  restart: unless-stopped

Standalone Run

# Set environment variables
export SMTP_HOST=smtp.mail.ru
export SMTP_PORT=587
export SMTPMAIL=noreply@luxmart.site
export SMTPPASSWORD=your_password
export REDIS_ADDR=localhost:6379

# Run the service
cd services/email-service
go run main.go

Troubleshooting

Emails Not Sending

  1. Check Redis connection:

    redis-cli ping
    

  2. Check email service logs:

    docker logs luxmart-email-service
    

  3. Verify SMTP credentials:

    # Test SMTP connection
    telnet smtp.mail.ru 587
    

  4. Check queue:

    redis-cli ZCARD email:queue
    

High Memory Usage

  • Reduce EMAIL_WORKER_COUNT
  • Increase EMAIL_RATE_LIMIT delay
  • Check for emails stuck in queue

Rate Limiting Issues

If you see "rate limit exceeded" errors:

  1. Increase EMAIL_RATE_LIMIT value
  2. Or reduce EMAIL_WORKER_COUNT
  3. Check SMTP provider limits

Dead Letter Queue Growing

Check DLQ for common error patterns:

# Get failed emails
redis-cli ZRANGE email:queue:dlq 0 -1

# Examine one
redis-cli ZRANGE email:queue:dlq 0 0 | jq

Common causes: - Invalid email addresses - SMTP authentication failures - SMTP server rejecting emails - Network connectivity issues

Best Practices

  1. Use appropriate priorities:
  2. High: OTP, password resets
  3. Normal: Order confirmations, account updates
  4. Low: Newsletters, promotional emails

  5. Language selection:

  6. Always pass user's preferred language
  7. Fallback to English if language not supported

  8. Error handling:

  9. Always check for errors when enqueueing
  10. Log failed email attempts
  11. Monitor DLQ regularly

  12. Template updates:

  13. Test templates before deployment
  14. Ensure all languages are updated
  15. Validate HTML rendering

  16. Rate limiting:

  17. Respect SMTP provider limits
  18. Adjust rate limit based on provider
  19. Monitor for throttling errors

  20. Monitoring:

  21. Track queue sizes
  22. Monitor success/failure rates
  23. Set up alerts for DLQ growth

Support

For email service issues: - Check logs: docker logs luxmart-email-service - Monitor Redis: redis-cli MONITOR - Contact: support@luxmart.site