IPC handlers
Introduction#
Registered ipcMain.handle routes for WhatsApp, Gmail, SMTP, and file import, including how errors come back to the renderer.
Project structure#
The IPC system spans three primary areas:
- Main process handlers: Centralized in the main process, exposing capabilities to the renderer via ipcMain.handle.
- Preload bridge: Exposes a controlled API surface to the renderer via contextBridge.
- Renderer integration: Components call preload APIs, receive events, and manage UI state.
graph TB subgraph "Renderer Process" BM["BulkMailer.jsx"] WF["WhatsAppForm.jsx"] GF["GmailForm.jsx"] SF["SMTPForm.jsx"] Preload["preload.js<br/>contextBridge exposeInMainWorld"] end subgraph "Main Process" Main["main.js<br/>ipcMain.handle registrations"] GH["gmail-handler.js<br/>Gmail handlers"] SH["smtp-handler.js<br/>SMTP handlers"] end BM --> Preload WF --> Preload GF --> Preload SF --> Preload Preload --> Main Main --> GH Main --> SH
Core components#
This section enumerates all registered IPC handlers and their responsibilities.
Gmail handlers
gmail-auth: Initiates OAuth2 authentication flow and stores tokens.
gmail-token: Checks for existing stored token.
send-email: Sends emails via Gmail API with progress events.
SMTP handlers
smtp-send: Sends emails via SMTP with progress events.
WhatsApp handlers
whatsapp-start-client: Initializes and authenticates a WhatsApp client, emits status and QR events.
whatsapp-send-messages: Sends personalized messages to a list of contacts.
whatsapp-import-contacts: Imports contacts from CSV or TXT files.
whatsapp-logout: Logs out the WhatsApp client and cleans up cached files.
File operations
import-email-list: Opens a file dialog to select email list files.
read-email-list-file: Reads and parses selected email list files.
Event emitters (renderer listeners)
onWhatsAppStatus: Receives status updates from the WhatsApp client.
onWhatsAppQR: Receives QR code data URL for authentication.
onWhatsAppSendStatus: Receives real-time send status updates.
onProgress: Receives email progress events.
Architecture overview#
The IPC architecture follows an event-driven model:
- Renderer process invokes preload APIs (ipcRenderer.invoke).
- Main process handles requests via ipcMain.handle and performs operations.
- Main process emits events (ipcRenderer.on) to the renderer for real-time updates.
- Results are returned via invoke promises; errors propagate as structured error objects.
sequenceDiagram
participant R as "Renderer (React)"
participant P as "Preload Bridge"
participant M as "Main Process"
participant S as "External Services"
R->>P : invoke("gmail-auth")
P->>M : ipcMain.handle("gmail-auth")
M->>S : Open OAuth2 browser window
S-->>M : Redirect with authorization code
M->>S : Exchange code for token
M-->>P : {success : true}
P-->>R : Promise resolved
Note over R,M : Real-time events via onWhatsAppStatus/onWhatsAppQR/onWhatsAppSendStatusDetailed component analysis#
WhatsApp IPC handlers#
The WhatsApp handlers orchestrate client lifecycle, authentication, messaging, and cleanup.
whatsapp-start-client
Responsibilities: Initialize WhatsApp client with local authentication, emit status and QR events, handle authentication lifecycle.
Parameters: None.
Return: Promise resolving to undefined or early return if client already running.
Events emitted: whatsapp-status, whatsapp-qr.
Error handling: Catches initialization failures and emits failure status.
whatsapp-send-messages
Responsibilities: Validate client readiness, iterate contacts, personalize messages, send to registered users, enforce delays, aggregate results.
Parameters: { contacts[], messageText }.
Return: { success: boolean, sent: number, failed: number }.
Events emitted: whatsapp-send-status.
Error handling: Per-contact error handling with retries and delays.
whatsapp-import-contacts
Responsibilities: Open file dialog, parse CSV or TXT, normalize contacts.
Parameters: None.
Return: Promise resolving to contacts[] or null.
Error handling: Graceful fallback to empty array on parse errors.
whatsapp-logout
Responsibilities: Logout client, cleanup cached files, reset UI state.
Parameters: None.
Return: { success: boolean, message: string }.
Events emitted: whatsapp-status, whatsapp-qr.
sequenceDiagram
participant UI as "WhatsAppForm.jsx"
participant BM as "BulkMailer.jsx"
participant P as "preload.js"
participant M as "main.js"
participant W as "WhatsApp Client"
UI->>BM : onClick("Connect to WhatsApp")
BM->>P : invoke("whatsapp-start-client")
P->>M : ipcMain.handle("whatsapp-start-client")
M->>W : new Client(LocalAuth)
M->>M : attach event listeners (qr, ready, authenticated, auth_failure, disconnected)
M->>P : emit("whatsapp-status", "Initializing...")
M->>P : emit("whatsapp-qr", dataUrl)
M->>P : emit("whatsapp-status", "Client is ready!")
P-->>BM : Promise resolvedGmail IPC handlers#
The Gmail handlers manage OAuth2 authentication and email sending.
gmail-auth
Responsibilities: Create OAuth2 client, generate auth URL, open browser window, handle redirect, exchange code for token, store token.
Parameters: None.
Return: { success: boolean, error?: string }.
Timeout: 5 minutes for completion.
Security: Requires environment variables for client ID and secret.
gmail-token
Responsibilities: Check for stored token.
Parameters: None.
Return: { success: boolean, hasToken: boolean }.
send-email
Responsibilities: Validate token, iterate recipients, send via Gmail API, emit progress events, aggregate results.
Parameters: { recipients[], subject, message, delay? }.
Return: { success: boolean, results[] }.
Events emitted: email-progress.
flowchart TD
Start(["invoke('gmail-auth')"]) --> CheckEnv["Check GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET"]
CheckEnv --> EnvOK{"Environment variables present?"}
EnvOK --> |No| ReturnErr["Return {success: false, error}"]
EnvOK --> |Yes| CreateOAuth["Create OAuth2 client"]
CreateOAuth --> GenAuthURL["Generate auth URL with scopes"]
GenAuthURL --> OpenBrowser["Open BrowserWindow with auth URL"]
OpenBrowser --> WaitRedirect["Wait for redirect to REDIRECT_URI"]
WaitRedirect --> HasCode{"Authorization code present?"}
HasCode --> |No| CloseWindow["Close window and return error"]
HasCode --> |Yes| Exchange["Exchange code for token"]
Exchange --> StoreToken["Store token in electron-store"]
StoreToken --> ReturnOK["Return {success: true}"]SMTP IPC handlers#
The SMTP handler manages SMTP configuration, connection verification, and email sending.
- smtp-send
- Responsibilities: Validate SMTP config, optionally save config (without password), verify connection, iterate recipients, send via SMTP, emit progress events, aggregate results.
- Parameters: { smtpConfig, recipients[], subject, message, delay?, saveCredentials? }.
- Return: { success: boolean, results[] }.
- Events emitted: email-progress.
File operations IPC handlers#
These handlers support importing and parsing email lists.
import-email-list
Responsibilities: Open file dialog for selecting email list files.
Parameters: None.
Return: Promise resolving to dialog result.
read-email-list-file
Responsibilities: Read file content, parse CSV or TXT, extract valid email addresses.
Parameters: filePath.
Return: Promise resolving to newline-separated emails or throws on error.
Renderer integration and event handling#
The renderer integrates with IPC through the preload bridge and updates UI state accordingly.
Preload API exposure
Exposes authenticateGmail, getGmailToken, sendEmail, sendSMTPEmail, importEmailList, readEmailListFile, and WhatsApp-related methods.
Provides event listeners: onWhatsAppStatus, onWhatsAppQR, onWhatsAppSendStatus, onProgress.
BulkMailer integration
Subscribes to WhatsApp status and QR events.
Validates forms, constructs payload objects, and awaits invoke promises.
Updates state based on results and errors.
Form components
WhatsAppForm: Manages QR display, status color, and logs.
GmailForm: Manages authentication status and email list import.
SMTPForm: Manages SMTP configuration and email list import.
sequenceDiagram
participant BM as "BulkMailer.jsx"
participant P as "preload.js"
participant M as "main.js"
participant GH as "gmail-handler.js"
participant SH as "smtp-handler.js"
BM->>P : invoke("send-email", payload)
P->>M : ipcMain.handle("send-email")
M->>GH : handleSendEmail(event, payload)
GH->>GH : iterate recipients, send via Gmail API
GH->>M : event.sender.send("email-progress", ...)
M-->>P : {success : true, results}
P-->>BM : Promise resolved
BM->>P : invoke("smtp-send", payload)
P->>M : ipcMain.handle("smtp-send")
M->>SH : handleSMTPSend(event, payload)
SH->>SH : iterate recipients, send via SMTP
SH->>M : event.sender.send("email-progress", ...)
M-->>P : {success : true, results}
P-->>BM : Promise resolvedDependency analysis#
The IPC handlers depend on external libraries and Electron APIs.
graph TB Main["main.js"] GH["gmail-handler.js"] SH["smtp-handler.js"] Preload["preload.js"] Utils["utils.js"] Main --> GH Main --> SH Main --> Utils GH --> GoogleApis["googleapis"] SH --> Nodemailer["nodemailer"] Main --> QRCode["qrcode"] Main --> Dialog["electron.dialog"] Main --> FS["fs"] Main --> CSV["csv-parser"]
Performance considerations#
- Rate limiting: Both Gmail and SMTP handlers implement configurable delays between sends to avoid rate limits and reduce load.
- Asynchronous processing: Long-running operations (initialization, authentication, file parsing) are handled asynchronously to keep the UI responsive.
- Event-driven updates: Real-time progress events minimize polling and improve perceived performance.
- Resource cleanup: WhatsApp client cleanup and file deletion prevent memory leaks and stale sessions.
Troubleshooting guide#
Common issues and resolutions:
WhatsApp authentication failures
Symptoms: QR not generated, authentication failure messages.
Causes: Headless browser issues, network problems, cached session conflicts.
Resolution: Retry initialization, ensure headless arguments are valid, clear cached files, and verify network connectivity.
Gmail authentication timeouts
Symptoms: OAuth window closes without token.
Causes: Redirect URI mismatch, missing environment variables, long redirect handling.
Resolution: Verify GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET, ensure REDIRECT_URI matches, and retry within timeout.
SMTP connection verification failures
Symptoms: Transport verification errors.
Causes: Incorrect host/port/credentials, TLS issues.
Resolution: Validate SMTP configuration, adjust secure flag, and test with a simple client.
File import errors
Symptoms: No contacts loaded, parsing errors.
Causes: Unsupported file types, malformed CSV/ TXT.
Resolution: Use supported formats (.csv, .txt), ensure correct column names or comma separation.
Security considerations#
- Context isolation: The preload script uses contextBridge to expose a minimal API surface, preventing direct Node.js access from the renderer.
- Environment validation: Gmail OAuth requires environment variables for client credentials; missing variables cause immediate failure.
- Token storage: Tokens are stored securely via electron-store; SMTP passwords are intentionally not saved for security.
- Input validation: Form components validate email formats and required fields before invoking IPC handlers.
- Error containment: Errors are returned as structured objects rather than thrown exceptions, reducing information leakage.
Conclusion#
Return { success, error } style payloads instead of throwing across IPC. The UI already expects that pattern.