src — email

Module: src-email Cohesion: 0.80 Members: 0

src — email

The src/email module provides a comprehensive, unified interface for email integration, encompassing IMAP (Internet Message Access Protocol) for receiving, SMTP (Simple Mail Transfer Protocol) for sending, and webhook functionality for event notifications. It is designed to abstract away the complexities of interacting with different email protocols and services, offering a consistent API for developers.

Important Note on Implementation: The ImapClient and SmtpClient within this module are mock implementations. They simulate email server behavior for development and testing purposes without requiring actual external email services or libraries. In a production environment, these clients would be replaced or integrated with robust third-party libraries like nodemailer for SMTP and node-imap for IMAP.

Module Architecture

The module is structured into three main parts:

  1. Types (src/email/types.ts): Defines all data structures and configurations used across the email system.
  2. Clients (src/email/client.ts): Provides low-level, protocol-specific (IMAP/SMTP) client functionalities. These are the mock implementations.
  3. Service (src/email/service.ts): Offers a high-level, unified API that orchestrates the IMAP and SMTP clients, manages webhooks, and handles polling/syncing. It follows a singleton pattern for easy access throughout the application.
graph TD
    subgraph Email Module
        A[EmailService] --> B(ImapClient)
        A --> C(SmtpClient)
        A --> D(WebhookManager)
        B -- Emits Events --> A
        C -- Emits Events --> A
        D -- Emits Events --> A
        A -- Uses --> E(EmailServiceConfig)
        B -- Uses --> F(ImapConfig)
        C -- Uses --> G(SmtpConfig)
        D -- Uses --> H(EmailWebhookConfig)
        A -- Emits Events --> App(Application)
    end
    style A fill:#f9f,stroke:#333,stroke-width:2px
    style B fill:#bbf,stroke:#333,stroke-width:2px
    style C fill:#bbf,stroke:#333,stroke-width:2px
    style D fill:#bfb,stroke:#333,stroke-width:2px
    style App fill:#eee,stroke:#333,stroke-width:2px

Core Concepts and Types (src/email/types.ts)

This file defines the foundational interfaces and types that govern data exchange and configuration within the email module.

Key Types

Default Configurations

The module exports DEFAULT_IMAP_CONFIG and DEFAULT_SMTP_CONFIG to provide sensible defaults for common settings like ports and security.

Client Implementations (src/email/client.ts)

This file contains the mock implementations of the IMAP and SMTP clients, along with general email utility functions.

Utility Functions

ImapClient (Mock Implementation)

The ImapClient class simulates an IMAP client, allowing operations like connecting, listing folders, selecting folders, searching, fetching messages, managing flags, moving/copying/deleting messages, and entering IDLE mode.

SmtpClient (Mock Implementation)

The SmtpClient class simulates an SMTP client for sending emails.

Service Layer (src/email/service.ts)

This file provides the high-level EmailService which acts as the primary interface for interacting with email functionalities. It integrates the IMAP and SMTP clients and adds webhook management and polling capabilities.

WebhookManager

Manages the registration, removal, and triggering of webhooks.

EmailService

The central component of the email module, orchestrating all functionalities.

Singleton Access

The EmailService is designed to be accessed as a singleton:

Usage Patterns

Initialization and Connection

import { getEmailService, EmailServiceConfig } from './email/index.js';

const config: EmailServiceConfig = {
  imap: {
    host: 'mock.imap.com',
    port: 993,
    secure: true,
    user: 'test@example.com',
    password: 'password',
  },
  smtp: {
    host: 'mock.smtp.com',
    port: 587,
    secure: false,
    user: 'test@example.com',
    password: 'password',
  },
  webhooks: [
    {
      url: 'https:class="hl-cmt">//my-app.com/email-events',
      events: ['message.received', 'message.sent'],
      secret: 'super-secret-key',
    },
  ],
  pollInterval: 30000, class="hl-cmt">// Poll every 30 seconds
};

const emailService = getEmailService(config);

async function startEmailService() {
  try {
    await emailService.connect();
    console.log('Email service connected.');

    emailService.on('message', (message) => {
      console.log(`New message received: ${message.subject} from ${message.from[0].address}`);
    });

    emailService.on('error', (error) => {
      console.error('Email service error:', error);
    });

    emailService.on('webhook-sent', (url, payload) => {
      console.log(`Webhook sent to ${url} for event ${payload.event}`);
    });

  } catch (error) {
    console.error('Failed to connect email service:', error);
  }
}

startEmailService();

Sending an Email

import { getEmailService } from './email/index.js';

const emailService = getEmailService(); class="hl-cmt">// Get the existing instance

async function sendTestEmail() {
  try {
    const result = await emailService.sendEmail({
      from: { name: 'My App', address: 'test@example.com' },
      to: 'recipient@example.com',
      subject: 'Hello from Email Service!',
      text: 'This is a test email sent via the Email Service.',
      html: &#39;<b>This is a test email</b> sent via the <i>Email Service</i>.&#39;,
    });
    console.log(&#39;Email sent successfully:&#39;, result.messageId);
  } catch (error) {
    console.error(&#39;Failed to send email:&#39;, error);
  }
}

sendTestEmail();

Fetching Messages

import { getEmailService } from &#39;./email/index.js&#39;;

const emailService = getEmailService();

async function fetchInboxMessages() {
  try {
    await emailService.selectFolder(&#39;INBOX&#39;);
    const uids = await emailService.search({ unseen: true });
    console.log(`Found ${uids.length} unseen messages.`);

    if (uids.length > 0) {
      const messages = await emailService.fetchMessages(uids);
      for (const message of messages) {
        console.log(`- Subject: ${message.subject}, From: ${message.from[0].address}`);
        await emailService.markAsRead(message.uid!, &#39;INBOX&#39;);
      }
    }
  } catch (error) {
    console.error(&#39;Failed to fetch messages:&#39;, error);
  }
}

fetchInboxMessages();

Event Handling

The EmailService (and its underlying clients) are EventEmitter instances, allowing you to subscribe to various events:

Extensibility and Real-World Integration

As noted, the ImapClient and SmtpClient are mock implementations. To transition to a production environment:

  1. Replace Client Logic: The ImapClient and SmtpClient classes would need to be re-implemented to use actual email client libraries (e.g., node-imap for IMAP, nodemailer for SMTP).
  2. Maintain Interface: Crucially, the public API (connect, send, fetch, search, etc.) and the emitted events of these client classes should remain consistent to avoid breaking the EmailService layer.
  3. Configuration: The ImapConfig and SmtpConfig types are designed to be compatible with common configurations for these libraries, making the transition smoother.
  4. Gmail Integration: The GmailConfig and related types are placeholders for potential future integration with the Gmail API, which offers a different set of capabilities beyond standard IMAP/SMTP.

This modular design allows the core EmailService and WebhookManager logic to remain stable while the underlying protocol implementations can be swapped out or enhanced.