Worker Mailer

repository·main·Indexed 42 days ago

https://github.com/zou-yu/worker-mailer

An SMTP client designed for the Cloudflare Workers runtime using Cloudflare TCP Sockets to send plain text, HTML, and attachments without external dependencies. Version 1.2.1 requires Node.js compatibility flags (nodejs_compat or nodejs_compat_v2) in wrangler.toml. Features include support for STARTTLS, multiple authentication methods (plain, login, cram-md5), and DSN overrides.

Tokens
4.9K
Snippets
17
Records
22
Agent score
52%

What's inside Worker Mailer

  1. Handle local development with modern JS frameworks

    main

    Since worker-mailer relies on Cloudflare-specific APIs (like cloudflare:sockets), it will not work in a standard Node.js local development environment. When using frameworks like Next.js, Nuxt, or SvelteKit, use conditional dynamic imports to switch between worker-mailer in production and a Node-compatible library (like nodemailer) in development.

    export default defineEventHandler(async event => {
      // Check if running in development environment
      if (import.meta.dev) {
        // Development: Use nodemailer (or any Node.js compatible email library)
        const nodemailer = await import('nodemailer')
        const transporter = nodemailer.default.createTransport()
        return await transporter.sendMail()
      } else {
        // Production: Use worker-mailer in Cloudflare Workers environment
        const { WorkerMailer } = await import('worker-mailer')
        const mailer = await WorkerMailer.connect()
        return await mailer.send()
      }
    })
  2. Quick Start: Connect and send an email

    main

    To use worker-mailer, first establish a connection using WorkerMailer.connect() with your SMTP server details, then use the returned instance to call .send().

    import { WorkerMailer } from 'worker-mailer'
    
    // Connect to SMTP server
    const mailer = await WorkerMailer.connect({
      credentials: {
        username: 'bob@acme.com',
        password: 'password',
      },
      authType: 'plain',
      host: 'smtp.acme.com',
      port: 587,
      secure: true,
    })
    
    // Send email
    await mailer.send({
      from: { name: 'Bob', email: 'bob@acme.com' },
      to: { name: 'Alice', email: 'alice@acme.com' },
      subject: 'Hello from Worker Mailer',
      text: 'This is a plain text message',
      html: '<h1\>Hello\</h1><p>This is an HTML message</p>',
    })
  3. Configure wrangler.toml for Cloudflare Workers

    main

    To use worker-mailer, you must enable Node.js compatibility in your wrangler.toml file. You can use either nodejs_compat or nodejs_compat_v2.

    compatibility_flags = ["nodejs_compat"]
    # or compatibility_flags = ["nodejs_compat_v2"]
  4. Configure Cloudflare Workers compatibility flags

    main

    To use worker-mailer, you must enable Node.js compatibility in your wrangler.toml file. You can use either nodejs_compat or nodejs_compat_v2.

    compatibility_flags = ["nodejs_compat"]
    # or compatibility_flags = ["nodejs_compat_v2"]
  5. SMTP Port and Connection Limitations

    main

    When using worker-mailer on Cloudflare Workers, be aware of the following constraints:

    • Port Restrictions: Outbound connections on port 25 are prohibited. Use ports like 587 or 465 instead.
    • Connection Limits: Each Worker instance has a limit on concurrent TCP connections. Ensure you properly close connections when finished to avoid exhausting limits.
  6. Troubleshooting: Port and Connection limits

    main

    When using worker-mailer on Cloudflare Workers, be aware of the following constraints:

    • Port Restriction: Cloudflare Workers block outbound connections on port 25. You must use other ports like 587 or 465.
    • Connection Limits: Each Worker instance has a limit on concurrent TCP connections. Ensure you close connections properly after use to avoid exhausting the limit.
  7. WorkerMailer.connect(options)

    main

    Creates a new SMTP connection. This method returns a mailer instance used to send emails.

    type WorkerMailerOptions = {
      host: string // SMTP server hostname
      port: number // SMTP server port (usually 587 or 465)
      secure?: boolean // Use TLS (default: false)
      startTls?: boolean // Upgrade to TLS if SMTP server supports (default: true)
      credentials?: {
        // SMTP authentication credentials
        username: string
        password: string
      }
      authType?:
        | 'plain'
        | 'login'
        | 'cram-md5'
        | Array<'plain' | 'login' | 'cram-md5'>
      logLevel?: LogLevel // Logging level (default: LogLevel.INFO)
      socketTimeoutMs?: number // Socket timeout in milliseconds
      responseTimeoutMs?: number // Server response timeout in milliseconds
      dsn?: {
        RET?: {
          HEADERS?: boolean
          FULL?: boolean
        }
        NOTIFY?: {
          DELAY?: boolean
          FAILURE?: boolean
          SUCCESS?: boolean
        }
      }
    }
  8. mailer.send(options)

    main

    Sends an email using an existing connection.

    type EmailOptions = {
      from: 
        | string
        | { name?: string; email: string }
      to: 
        | string
        | string[]
        | { name?: string; email: string }
        | Array<{ name?: string; email: string }>
      reply?: 
        | string
        | { name?: string; email: string }
      cc?: 
        | string
        | string[]
        | { name?: string; email: string }
        | Array<{ name?: string; email: string }>
      bcc?: 
        | string
        | string[]
        | { name?: string; email: string }
        | Array<{ name?: string; email: string }>
      subject: string // Email subject
      text?: string // Plain text content
      html?: string // HTML content
      headers?: Record<string, string> // Custom email headers
      attachments?: { filename: string; content: string; mimeType?: string }[] // Attachments, content must be base64-encoded
      dsnOverride?: 
      {
        envelopeId?: string | undefined
        RET?: { HEADERS?: boolean; FULL?: boolean }
        NOTIFY?: { DELAY?: boolean; FAILURE?: boolean; SUCCESS?: boolean }
      }
    }
  9. WorkerMailer.send() static method

    main

    Sends a one-off email without maintaining a persistent connection. This method takes two arguments: the connection options (WorkerMailerOptions) and the email options (EmailOptions).

    await WorkerMailer.send(
      {
        // WorkerMailerOptions
        host: 'smtp.acme.com',
        port: 587,
        credentials: {
          username: 'user',
          password: 'pass',
        },
      },
      {
        // EmailOptions
        from: 'sender@acme.com',
        to: 'recipient@acme.com',
        subject: 'Test',
        text: 'Hello',
        attachments: [
          {
            filename: 'test.txt',
            content: 'SGVsbG8gV29ybGQ=', // base64-encoded string for "Hello World"
            type: 'text/plain',
          },
        ],
      },
    )
  10. Configure DSN overrides for email delivery

    main

    The dsnOverride option allows you to specify Delivery Status Notification (DSN) parameters. This is useful for controlling how much information is returned regarding the delivery status of the email.

    Available Keys

    • envelopeId: A specific ID for the envelope.
    • RET (Return): Controls which headers are returned.
      • HEADERS: boolean
      • FULL: boolean
    • NOTIFY: Controls which notifications are sent.
      • DELAY: boolean
      • FAILURE: boolean
      • SUCCESS: boolean
    const email = new Email({
      from: 'sender@example.com',
      to: 'recipient@example.com',
      subject: 'DSN Test',
      text: 'Body',
      dsnOverride: {
        RET: { HEADERS: true },
        NOTIFY: { FAILURE: true, SUCCESS: true }
      }
    });
  11. Configure WorkerMailerOptions for SMTP connection

    main

    When connecting to an SMTP server using WorkerMailer.connect(options), provide a WorkerMailerOptions object. This object defines the connection parameters, authentication, and timeouts.

    Connection Settings

    • host: (string) The SMTP server hostname.
    • port: (number) The SMTP server port.
    • secure: (boolean, optional) If true, uses a secure connection from the start.
    • startTls: (boolean, optional) If true (default), attempts to upgrade the connection using STARTTLS. Set to false to disable TLS.

    Authentication

    • credentials: (object, optional) Contains username and password strings.
    • authType: (string | string[], optional) Specifies the preferred authentication method. Supported values are 'plain', 'login', or 'cram-md5'. You can provide a single string or an array of preferred types.

    Timeouts

    • socketTimeoutMs: (number, optional) Timeout for socket operations. Defaults to 60,000 ms.
    • responseTimeoutMs: (number, optional) Timeout for waiting for SMTP server responses. Defaults to 30,000 ms.

    DSN (Delivery Status Notifications)

    • dsn: (object, optional) Configures DSN capabilities.
      • RET: Specifies return options like HEADERS or FULL.
      • NOTIFY: Specifies notification triggers like DELAY, FAILURE, or SUCCESS.
    const options: WorkerMailerOptions = {
      host: 'smtp.example.com',
      port: 587,
      secure: false,
      startTls: true,
      credentials: {
        username: 'user@example.com',
        password: 'password123'
      },
      authType: ['login', 'plain'],
      socketTimeoutMs: 30000,
      responseTimeoutMs: 10000
    };