Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Email Sender

The Email Sender (mailer) module provides email delivery capabilities for the entire system. It operates as an asynchronous event-driven service that consumes email send requests from other modules via RabbitMQ and delivers them through a configured SMTP server.

Core Features

SMTP Integration

The module uses standard SMTP protocol for email delivery:

  • STARTTLS Support: Configurable TLS encryption for secure email transmission
  • Authentication: Username/password-based SMTP authentication
  • Plain Connection Option: Support for unencrypted connections (for testing or trusted networks)
  • Dynamic Configuration: SMTP settings can be reloaded without service restart

Event-Driven Architecture

All email sending is triggered through RabbitMQ events:

  • Asynchronous Processing: Email sending doesn’t block the calling service
  • Reliable Delivery: RabbitMQ ensures events are not lost if the mailer is temporarily unavailable
  • Decoupled Design: Other modules don’t need direct dependencies on mailer code

Template System

Pre-defined email templates with embedded assets:

  • HTML Templates: Rich HTML email templates with inline styling
  • Embedded Assets: Logo and other assets are compiled into the binary (no external files needed)
  • Template Types: Register verification, OTP codes, password reset, package expiration notifications

Architecture

Configuration Storage

SMTP configuration is stored in Redis using the Manage module’s config provider system:

  • Config Key: mailer
  • Hot Reload: The module periodically checks Redis for config changes and rebuilds the SMTP connection if needed
  • Sensitive Data Protection: Passwords are redacted in debug logs

Configuration fields:

  • host: SMTP server hostname
  • port: SMTP server port (typically 587 for STARTTLS, 25 for plain)
  • username: SMTP authentication username
  • password: SMTP authentication password
  • sender: Default sender email address (used when from is not specified)
  • starttls: Whether to use STARTTLS encryption

Event Consumption

The module consumes two types of events:

  1. Generic Email Events (MailSendCall): Direct email sending with full control over content

    • Queue: helium_mailer_send
    • Exchange: mailer (Direct)
    • Routing Key: send
  2. Template-based Email Events: Events from other modules (primarily Auth and Telecom) that trigger template rendering

    • Register verification emails
    • OTP email codes
    • Password reset emails
    • Package expiration notifications

Hooks (Event Processors)

Each hook implements the Processor pattern to handle specific event types:

  • MailerHook: Core processor for MailSendCall events, handles actual SMTP transmission
  • RegisterEmailHook: Processes user registration verification emails
  • OtpEmailHook: Processes one-time password emails for 2FA
  • ForgotPasswordEmailHook: Processes password reset emails
  • AllPackageExpiredHook: Processes telecom package expiration notifications

All hooks follow the standard pattern: receive event → render template (if needed) → publish MailSendCall → SMTP delivery.

Integration Points

With Auth Module

The mailer consumes three types of email events from Auth:

  • RegisterEmailSendCall: When a new user registers
  • OtpEmailSendCall: When OTP authentication is required
  • ForgotPasswordEmailSendCall: When a user requests password reset

With Telecom Module

  • AllPackageExpiredEvent: Sent when all of a user’s telecom packages expire

With Manage Module

  • Uses Manage’s config_provider to fetch SMTP configuration from Redis
  • SMTP settings can be updated via Manage’s admin configuration APIs

Email Sending Flow

When another module needs to send an email:

  1. The calling module publishes an event (either a specific template event or a generic MailSendCall)
  2. If it’s a template event, the corresponding hook receives it and:
    • Fetches necessary data from the database (e.g., user email)
    • Renders the HTML template
    • Publishes a MailSendCall event
  3. MailerHook receives the MailSendCall event
  4. SMTP connection is used to transmit the email
  5. Errors are logged but don’t crash the worker (events can be retried by RabbitMQ)

Development Notes

  • All email content is sent as HTML with Content-Type: text/html
  • The SMTP sender can be overridden per-email via the from field in MailSendCall
  • Email templates use the askama templating engine
  • The module doesn’t expose any gRPC services (it’s worker-only)
  • All processors follow the Processor pattern (not OOP)
  • Email addresses are validated before sending; invalid addresses result in Error::InvalidInput
  • The module doesn’t track email delivery status or bounces (delegated to SMTP server)

Worker Setup

The mailer runs as a dedicated worker process that needs:

  • PostgreSQL connection (for template data like user emails)
  • Redis connection (for SMTP configuration)
  • RabbitMQ connection (for event consumption)

Refer to the helium-server deployment documentation for worker configuration details.