Spam & Virus Scanning
Relevant source files
The following files were used as context for generating this wiki page:The email platform incorporates optional but recommended modules for spam filtering and virus scanning to protect users and maintain service integrity. These features are integrated into the inbound email processing pipeline and leverage external, industry-standard tools: Rspamd for spam detection and ClamAV for virus scanning. When enabled, every incoming email and its attachments are analyzed before being delivered to a user's inbox.
This system is designed to be fail-open for availability; if scanning services are unavailable, emails are treated as clean to avoid disrupting mail flow. The results of the scans, particularly the spam score, are stored with the message metadata for future reference and analysis.
Sources: blueprint.md:71, services/api/src/worker.ts:13-14, services/api/src/services/spamFilter.ts:44-54, services/api/src/services/virusScanner.ts:35-40
Architecture Overview
Spam and virus scanning occurs within the Email Worker service, which processes emails from a queue. Before an email is persisted to the database, the worker first scans all attachments for viruses. If a virus is detected, processing is halted. If attachments are clean, the entire raw email content is then sent for a spam check. Based on the spam score and resulting action, the email may be rejected. If it passes all checks, it is saved to the database.
The following diagram illustrates the high-level data flow for inbound email processing with scanning enabled.
This diagram shows the email processing pipeline, including the virus and spam scanning steps.
Sources: services/api/src/worker.ts:182-243
Spam Filtering (Rspamd)
Spam filtering is handled by integrating with an Rspamd instance. The communication occurs over HTTP.
Sources: services/api/src/services/spamFilter.ts, blueprint.md:71
Spam Check Process
The checkSpam function sends the raw email content to the Rspamd /checkv2 endpoint. The sender's IP address can be included in the request headers for more accurate scoring. Rspamd analyzes the email and returns a JSON object containing a score, a recommended action, and a list of symbols that contributed to the score.
The following sequence diagram shows the interaction between the Email Worker and Rspamd.
This diagram illustrates the sequence of a spam check request.
Sources: services/api/src/services/spamFilter.ts:25-56
Spam Check Result
The SpamCheckResult interface defines the structure of the data returned after a spam check.
| Field | Type | Description |
|---|---|---|
score | number | The numerical spam score assigned by Rspamd. |
requiredScore | number | The score threshold at which an email is considered spam. |
isSpam | boolean | True if score is greater than or equal to requiredScore. |
action | string | The action recommended by Rspamd (e.g., 'no action', 'reject'). |
symbols | Record<string, ...> | An object detailing the Rspamd symbols that were triggered. |
messageId | string | The message ID assigned by Rspamd. |
Sources: services/api/src/services/spamFilter.ts:8-16
Actions and Logic
Based on the SpamCheckResult, the system decides how to handle the email:
shouldRejectEmail(result): Returnstrueif the action from Rspamd is'reject'. In the worker, this causes an error to be thrown, preventing the email from being saved.shouldQuarantineEmail(result): Returnstrueif the action is'soft reject'or ifisSpamis true. This is available for future quarantine functionality.
The final spam score is saved in the spamScore field of the Message model in the database.
Sources: services/api/src/services/spamFilter.ts:90-101, services/api/src/worker.ts:233-237, services/api/src/worker.ts:245
Virus Scanning (ClamAV)
Virus scanning is performed on email attachments using an integration with a ClamAV daemon. Communication is handled via a TCP socket.
Sources: services/api/src/services/virusScanner.ts, deployment_guide.md:204
Virus Scan Process
The scanBuffer function connects to the ClamAV daemon, sends the data using the INSTREAM command, and awaits a response. The function is designed to be resilient; if the ClamAV service is unavailable or the scan times out, it defaults to marking the file as clean to ensure email delivery is not blocked.
The persistAttachments function in the worker iterates through all attachments, calling scanBuffer for each one. If any attachment is found to contain a virus, the entire email processing is aborted by throwing an error.
This diagram shows the sequence of a virus scan request for a single buffer.
Sources: services/api/src/services/virusScanner.ts:23-88, services/api/src/worker.ts:98-114
Scan Result
The ScanResult interface defines the outcome of a scan.
| Field | Type | Description |
|---|---|---|
isClean | boolean | true if no virus was detected, false otherwise. |
virus | string (optional) | The name of the detected virus if isClean is false. |
error | string (optional) | An error message if the scan failed (e.g., timeout, connection error). |
Sources: services/api/src/services/virusScanner.ts:8-13
Logic in the Email Worker
The email worker follows a strict process for security scanning.
This flowchart details the decision logic for virus and spam scanning within the email worker.
Sources: services/api/src/worker.ts:95-114, services/api/src/worker.ts:226-237
Configuration and Deployment
Both Rspamd and ClamAV are optional services that can be enabled in the production Docker Compose setup. Their integration is controlled via environment variables in the API service.
| Environment Variable | Service | Default Value | Description |
|---|---|---|---|
RSPAMD_URL | Rspamd | http://rspamd:11333 | The URL for the Rspamd HTTP service. |
SPAM_THRESHOLD | Rspamd | 5.0 | The score at which an email is considered spam. |
CLAMAV_HOST | ClamAV | clamav | The hostname for the ClamAV daemon. |
CLAMAV_PORT | ClamAV | 3310 | The TCP port for the ClamAV daemon. |
CLAMAV_TIMEOUT | ClamAV | 30000 | Timeout in milliseconds for a virus scan. |
To enable these services, you must uncomment the clamav and rspamd service definitions in the docker-compose.prod.yml file.
Sources: services/api/src/services/spamFilter.ts:18-19, services/api/src/services/virusScanner.ts:15-17, deployment_guide.md:202-219
Summary
The spam and virus scanning system provides a critical layer of security for the email platform. By integrating with Rspamd and ClamAV, it effectively identifies and blocks malicious content before it reaches end-users. The implementation is centralized in the email processing worker, ensuring all incoming mail is consistently scanned. The system is configurable and designed with a fail-open approach to prioritize service availability while still offering robust protection.
Sources: blueprint.md:71, services/api/src/worker.ts