Bulk Messaging System

An Electron Desktop app for marketing campaign & broadcast management, using either whatsapp, gmail or a SMTP server

UI service integration and IPC communication

Introduction#

Preload-exposed APIs, how forms call them, and where Pyodide fits for offline contact parsing.

Project structure#

The Electron application is organized into:

  • UI layer: React components under electron/src/ui and electron/src/components
  • Electron main process: electron/src/electron/main.js orchestrates windows, IPC handlers, and services
  • Preload bridge: electron/src/electron/preload.js exposes a controlled API surface to the renderer
  • Services: Gmail and SMTP handlers under electron/src/electron
  • Pyodide utilities: electron/src/utils/pyodide.js and Python scripts under electron/dist-react/py and electron/public/py

Core components#

  • Electron main process: Creates the BrowserWindow with context isolation enabled, registers IPC handlers for Gmail, SMTP, and WhatsApp, and manages the WhatsApp client lifecycle.
  • Preload bridge: Exposes a typed API surface to the renderer via contextBridge, wrapping ipcRenderer.invoke and ipcRenderer.on.
  • React UI: BulkMailer coordinates tabs and state, wires UI events to preload APIs, and renders real-time status updates.
  • Pyodide integration: Dynamically loads Pyodide and executes a Python script to parse manual phone numbers in the renderer.

Key responsibilities:

  • Secure exposure of Node.js capabilities through a minimal, typed API
  • Real-time status updates via event-driven IPC channels
  • Controlled rate-limiting and error propagation across processes
  • Browser-based Python execution for contact parsing

Architecture overview#

The UI communicates with the main process using two primary patterns:

  • Request-response via ipcRenderer.invoke and ipcMain.handle for synchronous operations
  • Event streaming via ipcRenderer.on and event.sender.send for progress/status updates

Detailed component analysis#

IPC handlers and UI coordination#

  • Gmail authentication and sending:
  • Preload exposes authenticateGmail, getGmailToken, and sendEmail
  • Main registers ipcMain.handle for gmail-auth, gmail-token, and send-email
  • Gmail handler opens an OAuth window, exchanges tokens, stores credentials, and streams progress via email-progress events
  • SMTP sending:
  • Preload exposes sendSMTPEmail
  • Main registers smtp-send handler that verifies transport, sends emails, and streams progress
  • WhatsApp integration:
  • Preload exposes startWhatsAppClient, logoutWhatsApp, sendWhatsAppMessages, importWhatsAppContacts, and status listeners
  • Main creates a WhatsApp client with QR generation, emits status and QR events, and handles mass messaging with per-contact delays

Preload script and security context#

  • The preload script uses contextBridge.exposeInMainWorld to publish a single API object electronAPI
  • It wraps:
  • Gmail: authenticateGmail, getGmailToken, sendEmail
  • SMTP: sendSMTPEmail
  • File operations: importEmailList, readEmailListFile
  • Progress: onProgress
  • WhatsApp: startWhatsAppClient, logoutWhatsApp, sendWhatsAppMessages, importWhatsAppContacts, and three status listeners
  • Security settings in BrowserWindow webPreferences:
  • nodeIntegration: false
  • contextIsolation: true
  • enableRemoteModule: false
  • webSecurity: true
  • preload path set to preload.js

Pyodide integration for browser-based Python execution#

  • The UI invokes parseManualNumbers from BulkMailer.jsx, which calls a utility in pyodide.js
  • pyodide.js dynamically loads Pyodide from a CDN, initializes it, loads the Python script from the app’s built resources, and executes a function that parses phone numbers
  • The Python script cleans and validates phone numbers, supports name-number pairs, and returns structured contact data

UI update coordination and status streams#

  • WhatsApp status and QR updates:
  • Main process emits “whatsapp-status”, “whatsapp-qr”, and “whatsapp-send-status”
  • Preload forwards these via ipcRenderer.on listeners
  • BulkMailer subscribes in useEffect and updates local state for display
  • Email progress:
  • Gmail and SMTP handlers send “email-progress” events during batch operations
  • Preload exposes onProgress; BulkMailer uses it to render live progress and results

Dependency analysis#

  • UI depends on preload for IPC primitives and on pyodide.js for Python parsing
  • Preload depends on main process handlers for all operations
  • Main process handlers depend on external libraries (Google APIs, Nodemailer, WhatsApp Web)
  • Build system uses Vite to bundle the UI and serve from./dist-react

Performance considerations#

  • Rate limiting: Both Gmail and SMTP handlers introduce delays between emails to avoid throttling and respect provider limits
  • Batch processing: WhatsApp sends messages with deliberate pauses to prevent rate limits and improve reliability
  • Resource cleanup: Main process deletes cached WhatsApp files on logout and app close to free disk space and avoid stale sessions
  • UI responsiveness: Event-driven updates keep the UI responsive while long-running tasks execute in the main process

Troubleshooting guide#

Common issues and resolutions:

  • Electron API not available in renderer:
  • Ensure preload is correctly injected via webPreferences.preload and that the app is running in Electron (not a static HTML page)
  • Gmail authentication failures:
  • Verify environment variables for client ID and secret; check OAuth redirect URI and timeouts
  • SMTP connection errors:
  • Confirm host/port/credentials; note that TLS verification is disabled for self-signed certs
  • WhatsApp QR loading failures:
  • Retry initialization; check console for QR generation errors; ensure headless mode Puppeteer arguments are valid
  • Pyodide load failures:
  • Confirm the Python script is bundled and reachable at the expected path; check network connectivity for CDN load

Conclusion#

If window.api is undefined, fix preload first. Everything else in the forms depends on that bridge.