spamscanner 6.0.0 → 6.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +569 -42
- package/dist/cjs/arf.cjs +539 -0
- package/dist/cjs/arf.cjs.map +7 -0
- package/dist/cjs/cli.cjs +4729 -0
- package/dist/cjs/cli.cjs.map +7 -0
- package/dist/cjs/{index.js → index.cjs} +1677 -52
- package/dist/cjs/index.cjs.map +7 -0
- package/dist/esm/arf.js +514 -0
- package/dist/esm/arf.js.map +7 -0
- package/dist/esm/cli.js +4713 -0
- package/dist/esm/cli.js.map +7 -0
- package/dist/esm/index.js +1676 -51
- package/dist/esm/index.js.map +4 -4
- package/dist/types/arf.d.ts +129 -0
- package/dist/types/auth.d.ts +157 -0
- package/dist/types/enhanced-idn-detector.d.ts +236 -0
- package/dist/types/get-attributes.d.ts +148 -0
- package/dist/types/index.d.ts +959 -0
- package/dist/types/is-arbitrary.d.ts +231 -0
- package/dist/types/reputation.d.ts +60 -0
- package/package.json +13 -4
- package/dist/cjs/index.js.map +0 -7
package/README.md
CHANGED
|
@@ -1,19 +1,26 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
>
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
1
|
+
<h1 align="center">
|
|
2
|
+
<a href="https://spamscanner.net"><img src="https://raw.githubusercontent.com/spamscanner/spamscanner/master/media/spamscanner.png" alt="spamscanner" /></a>
|
|
3
|
+
</h1>
|
|
4
|
+
<div align="center">
|
|
5
|
+
<a href="https://github.com/spamscanner/spamscanner/actions/workflows/ci.yml"><img src="https://github.com/spamscanner/spamscanner/actions/workflows/ci.yml/badge.svg" alt="build status" /></a>
|
|
6
|
+
<a href="https://github.com/sindresorhus/xo"><img src="https://img.shields.io/badge/code_style-XO-5ed9c7.svg" alt="code style" /></a>
|
|
7
|
+
<a href="https://github.com/prettier/prettier"><img src="https://img.shields.io/badge/styled_with-prettier-ff69b4.svg" alt="styled with prettier" /></a>
|
|
8
|
+
<a href="https://lass.js.org"><img src="https://img.shields.io/badge/made_with-lass-95CC28.svg" alt="made with lass" /></a>
|
|
9
|
+
<a href="LICENSE"><img src="https://img.shields.io/github/license/spamscanner/spamscanner.svg" alt="license" /></a>
|
|
10
|
+
</div>
|
|
11
|
+
<br />
|
|
12
|
+
<div align="center">
|
|
13
|
+
Spam Scanner is the best <a href="https://en.wikipedia.org/wiki/Anti-spam_techniques" target="_blank">anti-spam</a>, <a href="https://en.wikipedia.org/wiki/Email_filtering" target="_blank">email filtering</a>, and <a href="https://en.wikipedia.org/wiki/Phishing" target="_blank">phishing prevention</a> service.
|
|
14
|
+
</div>
|
|
15
|
+
<hr />
|
|
16
|
+
<div align="center">
|
|
17
|
+
Spam Scanner is a drop-in replacement and the best alternative to SpamAssassin, rspamd, SpamTitan, and more.
|
|
18
|
+
</div>
|
|
19
|
+
<hr />
|
|
11
20
|
|
|
12
21
|
> \[!NOTE]
|
|
13
22
|
> Spam Scanner is actively maintained and used in production at [Forward Email](https://forwardemail.net) to protect millions of emails daily.
|
|
14
23
|
|
|
15
|
-
---
|
|
16
|
-
|
|
17
24
|
|
|
18
25
|
## Table of Contents
|
|
19
26
|
|
|
@@ -59,6 +66,19 @@
|
|
|
59
66
|
* [Selective Feature Disabling](#selective-feature-disabling)
|
|
60
67
|
* [Custom Timeout](#custom-timeout)
|
|
61
68
|
* [Custom Logger](#custom-logger)
|
|
69
|
+
* [CLI (Command Line Interface)](#cli-command-line-interface)
|
|
70
|
+
* [CLI Installation](#cli-installation)
|
|
71
|
+
* [Commands](#commands)
|
|
72
|
+
* [Exit Codes](#exit-codes)
|
|
73
|
+
* [CLI Examples](#cli-examples)
|
|
74
|
+
* [ARF (Abuse Reporting Format)](#arf-abuse-reporting-format)
|
|
75
|
+
* [Parsing ARF Reports](#parsing-arf-reports)
|
|
76
|
+
* [Creating ARF Reports](#creating-arf-reports)
|
|
77
|
+
* [ARF Result Object](#arf-result-object)
|
|
78
|
+
* [Mail Server Integration](#mail-server-integration)
|
|
79
|
+
* [Postfix Integration](#postfix-integration)
|
|
80
|
+
* [Dovecot Integration](#dovecot-integration)
|
|
81
|
+
* [TCP Server Mode](#tcp-server-mode)
|
|
62
82
|
* [Performance](#performance)
|
|
63
83
|
* [Benchmarks](#benchmarks)
|
|
64
84
|
* [Optimization Tips](#optimization-tips)
|
|
@@ -282,27 +302,27 @@ graph TB
|
|
|
282
302
|
C --> D[Language Detection]
|
|
283
303
|
D --> E[Tokenization]
|
|
284
304
|
E --> F[Naive Bayes Classification]
|
|
285
|
-
|
|
305
|
+
|
|
286
306
|
B --> G[Phishing Detection]
|
|
287
307
|
G --> G1[IDN Homograph Check]
|
|
288
308
|
G --> G2[Confusables Analysis]
|
|
289
309
|
G --> G3[URL Analysis]
|
|
290
|
-
|
|
310
|
+
|
|
291
311
|
B --> H[Attachment Scanning]
|
|
292
312
|
H --> H1[Virus Scan]
|
|
293
313
|
H --> H2[Executable Check]
|
|
294
314
|
H --> H3[Macro Detection]
|
|
295
315
|
H --> H4[NSFW Detection]
|
|
296
|
-
|
|
316
|
+
|
|
297
317
|
B --> I[Content Analysis]
|
|
298
318
|
I --> I1[Toxicity Detection]
|
|
299
319
|
I --> I2[Pattern Recognition]
|
|
300
|
-
|
|
320
|
+
|
|
301
321
|
F --> J[Result Aggregation]
|
|
302
322
|
G --> J
|
|
303
323
|
H --> J
|
|
304
324
|
I --> J
|
|
305
|
-
|
|
325
|
+
|
|
306
326
|
J --> K{Is Spam?}
|
|
307
327
|
K -->|Yes| L[Spam Result]
|
|
308
328
|
K -->|No| M[Ham Result]
|
|
@@ -317,12 +337,12 @@ sequenceDiagram
|
|
|
317
337
|
participant Classifier
|
|
318
338
|
participant ClamAV
|
|
319
339
|
participant TensorFlow
|
|
320
|
-
|
|
340
|
+
|
|
321
341
|
Client->>Scanner: scan(email)
|
|
322
342
|
Scanner->>Scanner: Parse Email
|
|
323
343
|
Scanner->>Scanner: Extract URLs
|
|
324
344
|
Scanner->>Scanner: Detect Language
|
|
325
|
-
|
|
345
|
+
|
|
326
346
|
par Parallel Detection
|
|
327
347
|
Scanner->>Classifier: Classify Tokens
|
|
328
348
|
Scanner->>ClamAV: Scan Attachments
|
|
@@ -331,7 +351,7 @@ sequenceDiagram
|
|
|
331
351
|
Scanner->>Scanner: Check Phishing
|
|
332
352
|
Scanner->>Scanner: Check Macros
|
|
333
353
|
end
|
|
334
|
-
|
|
354
|
+
|
|
335
355
|
Scanner->>Scanner: Aggregate Results
|
|
336
356
|
Scanner->>Client: Return Result
|
|
337
357
|
```
|
|
@@ -344,20 +364,20 @@ graph LR
|
|
|
344
364
|
A --> C[Classifiers]
|
|
345
365
|
A --> D[Detectors]
|
|
346
366
|
A --> E[Analyzers]
|
|
347
|
-
|
|
367
|
+
|
|
348
368
|
B --> B1[Email Parser]
|
|
349
369
|
B --> B2[Tokenizer]
|
|
350
370
|
B --> B3[Preprocessor]
|
|
351
|
-
|
|
371
|
+
|
|
352
372
|
C --> C1[Naive Bayes]
|
|
353
373
|
C --> C2[TensorFlow NSFW]
|
|
354
374
|
C --> C3[TensorFlow Toxicity]
|
|
355
|
-
|
|
375
|
+
|
|
356
376
|
D --> D1[Phishing Detector]
|
|
357
377
|
D --> D2[Virus Scanner]
|
|
358
378
|
D --> D3[Macro Detector]
|
|
359
379
|
D --> D4[Executable Detector]
|
|
360
|
-
|
|
380
|
+
|
|
361
381
|
E --> E1[Language Analyzer]
|
|
362
382
|
E --> E2[URL Analyzer]
|
|
363
383
|
E --> E3[Pattern Analyzer]
|
|
@@ -465,16 +485,16 @@ import SpamScanner from 'spamscanner';
|
|
|
465
485
|
const scanner = new SpamScanner({
|
|
466
486
|
// Enable performance metrics
|
|
467
487
|
enablePerformanceMetrics: true,
|
|
468
|
-
|
|
488
|
+
|
|
469
489
|
// Filter to supported languages
|
|
470
490
|
supportedLanguages: ['en', 'es', 'fr', 'de'],
|
|
471
|
-
|
|
491
|
+
|
|
472
492
|
// Enable macro detection
|
|
473
493
|
enableMacroDetection: true,
|
|
474
|
-
|
|
494
|
+
|
|
475
495
|
// Set scan timeout
|
|
476
496
|
timeout: 30000,
|
|
477
|
-
|
|
497
|
+
|
|
478
498
|
// Custom ClamAV configuration
|
|
479
499
|
clamscan: {
|
|
480
500
|
preference: 'clamdscan',
|
|
@@ -954,7 +974,7 @@ The `scan()` method returns a comprehensive result object:
|
|
|
954
974
|
// Overall spam classification
|
|
955
975
|
isSpam: boolean,
|
|
956
976
|
message: string, // 'Ham' or 'Spam: <reasons>'
|
|
957
|
-
|
|
977
|
+
|
|
958
978
|
// Detection results
|
|
959
979
|
results: {
|
|
960
980
|
// Classification details
|
|
@@ -962,7 +982,7 @@ The `scan()` method returns a comprehensive result object:
|
|
|
962
982
|
category: 'spam' | 'ham',
|
|
963
983
|
probability: number
|
|
964
984
|
},
|
|
965
|
-
|
|
985
|
+
|
|
966
986
|
// Phishing detection
|
|
967
987
|
phishing: [
|
|
968
988
|
{
|
|
@@ -971,7 +991,7 @@ The `scan()` method returns a comprehensive result object:
|
|
|
971
991
|
message: string
|
|
972
992
|
}
|
|
973
993
|
],
|
|
974
|
-
|
|
994
|
+
|
|
975
995
|
// Executable detection
|
|
976
996
|
executables: [
|
|
977
997
|
{
|
|
@@ -981,7 +1001,7 @@ The `scan()` method returns a comprehensive result object:
|
|
|
981
1001
|
risk: 'high' | 'medium' | 'low'
|
|
982
1002
|
}
|
|
983
1003
|
],
|
|
984
|
-
|
|
1004
|
+
|
|
985
1005
|
// Macro detection
|
|
986
1006
|
macros: [
|
|
987
1007
|
{
|
|
@@ -989,10 +1009,10 @@ The `scan()` method returns a comprehensive result object:
|
|
|
989
1009
|
message: string
|
|
990
1010
|
}
|
|
991
1011
|
],
|
|
992
|
-
|
|
1012
|
+
|
|
993
1013
|
// Arbitrary results (custom detections)
|
|
994
1014
|
arbitrary: [],
|
|
995
|
-
|
|
1015
|
+
|
|
996
1016
|
// Virus scanning
|
|
997
1017
|
viruses: [
|
|
998
1018
|
{
|
|
@@ -1001,7 +1021,7 @@ The `scan()` method returns a comprehensive result object:
|
|
|
1001
1021
|
type: 'virus'
|
|
1002
1022
|
}
|
|
1003
1023
|
],
|
|
1004
|
-
|
|
1024
|
+
|
|
1005
1025
|
// Pattern recognition
|
|
1006
1026
|
patterns: {
|
|
1007
1027
|
credit_cards: number,
|
|
@@ -1013,10 +1033,10 @@ The `scan()` method returns a comprehensive result object:
|
|
|
1013
1033
|
dates: number,
|
|
1014
1034
|
file_paths: number
|
|
1015
1035
|
},
|
|
1016
|
-
|
|
1036
|
+
|
|
1017
1037
|
// IDN homograph attack detection
|
|
1018
1038
|
idnHomographAttack: [],
|
|
1019
|
-
|
|
1039
|
+
|
|
1020
1040
|
// Toxicity detection (array of results)
|
|
1021
1041
|
toxicity: [
|
|
1022
1042
|
{
|
|
@@ -1026,7 +1046,7 @@ The `scan()` method returns a comprehensive result object:
|
|
|
1026
1046
|
description: string
|
|
1027
1047
|
}
|
|
1028
1048
|
],
|
|
1029
|
-
|
|
1049
|
+
|
|
1030
1050
|
// NSFW detection (array of results)
|
|
1031
1051
|
nsfw: [
|
|
1032
1052
|
{
|
|
@@ -1038,13 +1058,13 @@ The `scan()` method returns a comprehensive result object:
|
|
|
1038
1058
|
}
|
|
1039
1059
|
]
|
|
1040
1060
|
},
|
|
1041
|
-
|
|
1061
|
+
|
|
1042
1062
|
// All URLs extracted from email
|
|
1043
1063
|
links: string[],
|
|
1044
|
-
|
|
1064
|
+
|
|
1045
1065
|
// Tokens extracted from email
|
|
1046
1066
|
tokens: string[],
|
|
1047
|
-
|
|
1067
|
+
|
|
1048
1068
|
// Email metadata
|
|
1049
1069
|
mail: {
|
|
1050
1070
|
from: object,
|
|
@@ -1055,7 +1075,7 @@ The `scan()` method returns a comprehensive result object:
|
|
|
1055
1075
|
attachments: object[],
|
|
1056
1076
|
headers: object
|
|
1057
1077
|
},
|
|
1058
|
-
|
|
1078
|
+
|
|
1059
1079
|
// Performance metrics (if enabled)
|
|
1060
1080
|
metrics: {
|
|
1061
1081
|
totalTime: number, // milliseconds
|
|
@@ -1178,6 +1198,508 @@ const scanner = new SpamScanner({
|
|
|
1178
1198
|
---
|
|
1179
1199
|
|
|
1180
1200
|
|
|
1201
|
+
## CLI (Command Line Interface)
|
|
1202
|
+
|
|
1203
|
+
SpamScanner provides a command-line interface for scanning emails directly from the terminal or integrating with mail servers.
|
|
1204
|
+
|
|
1205
|
+
### CLI Installation
|
|
1206
|
+
|
|
1207
|
+
SpamScanner can be installed via npm or as a standalone binary. The standalone binary includes Node.js and all dependencies, so no additional runtime is required.
|
|
1208
|
+
|
|
1209
|
+
#### Install via npm (requires Node.js)
|
|
1210
|
+
|
|
1211
|
+
```bash
|
|
1212
|
+
# Install globally
|
|
1213
|
+
npm install -g spamscanner
|
|
1214
|
+
|
|
1215
|
+
# Or use npx without installing
|
|
1216
|
+
npx spamscanner --help
|
|
1217
|
+
```
|
|
1218
|
+
|
|
1219
|
+
#### Install Standalone Binary
|
|
1220
|
+
|
|
1221
|
+
##### macOS
|
|
1222
|
+
|
|
1223
|
+
```bash
|
|
1224
|
+
# Using curl (Intel or Apple Silicon - auto-detected)
|
|
1225
|
+
curl -fsSL https://github.com/spamscanner/spamscanner/releases/latest/download/spamscanner-darwin-$(uname -m | sed 's/x86_64/x64/' | sed 's/aarch64/arm64/' | sed 's/arm64/arm64/') -o /usr/local/bin/spamscanner
|
|
1226
|
+
chmod +x /usr/local/bin/spamscanner
|
|
1227
|
+
|
|
1228
|
+
# Or download manually for Intel Mac
|
|
1229
|
+
curl -fsSL https://github.com/spamscanner/spamscanner/releases/latest/download/spamscanner-darwin-x64 -o /usr/local/bin/spamscanner
|
|
1230
|
+
chmod +x /usr/local/bin/spamscanner
|
|
1231
|
+
|
|
1232
|
+
# Or download manually for Apple Silicon (M1/M2/M3)
|
|
1233
|
+
curl -fsSL https://github.com/spamscanner/spamscanner/releases/latest/download/spamscanner-darwin-arm64 -o /usr/local/bin/spamscanner
|
|
1234
|
+
chmod +x /usr/local/bin/spamscanner
|
|
1235
|
+
```
|
|
1236
|
+
|
|
1237
|
+
##### Linux
|
|
1238
|
+
|
|
1239
|
+
```bash
|
|
1240
|
+
# Download and install to /usr/local/bin
|
|
1241
|
+
sudo curl -fsSL https://github.com/spamscanner/spamscanner/releases/latest/download/spamscanner-linux-x64 -o /usr/local/bin/spamscanner
|
|
1242
|
+
sudo chmod +x /usr/local/bin/spamscanner
|
|
1243
|
+
|
|
1244
|
+
# Or install to user directory (no sudo required)
|
|
1245
|
+
mkdir -p ~/.local/bin
|
|
1246
|
+
curl -fsSL https://github.com/spamscanner/spamscanner/releases/latest/download/spamscanner-linux-x64 -o ~/.local/bin/spamscanner
|
|
1247
|
+
chmod +x ~/.local/bin/spamscanner
|
|
1248
|
+
# Add to PATH if not already: export PATH="$HOME/.local/bin:$PATH"
|
|
1249
|
+
```
|
|
1250
|
+
|
|
1251
|
+
##### Windows
|
|
1252
|
+
|
|
1253
|
+
```powershell
|
|
1254
|
+
# Using PowerShell (run as Administrator)
|
|
1255
|
+
Invoke-WebRequest -Uri "https://github.com/spamscanner/spamscanner/releases/latest/download/spamscanner-win-x64.exe" -OutFile "C:\Program Files\spamscanner\spamscanner.exe"
|
|
1256
|
+
# Add to PATH via System Properties > Environment Variables
|
|
1257
|
+
|
|
1258
|
+
# Or download to current directory
|
|
1259
|
+
Invoke-WebRequest -Uri "https://github.com/spamscanner/spamscanner/releases/latest/download/spamscanner-win-x64.exe" -OutFile ".\spamscanner.exe"
|
|
1260
|
+
```
|
|
1261
|
+
|
|
1262
|
+
##### Verify Installation
|
|
1263
|
+
|
|
1264
|
+
```bash
|
|
1265
|
+
# Check version
|
|
1266
|
+
spamscanner version
|
|
1267
|
+
|
|
1268
|
+
# Check for updates
|
|
1269
|
+
spamscanner update
|
|
1270
|
+
```
|
|
1271
|
+
|
|
1272
|
+
#### Automatic Updates
|
|
1273
|
+
|
|
1274
|
+
SpamScanner CLI automatically checks for updates once every 24 hours and displays a notification if a new version is available. You can also manually check for updates:
|
|
1275
|
+
|
|
1276
|
+
```bash
|
|
1277
|
+
# Check for updates
|
|
1278
|
+
spamscanner update
|
|
1279
|
+
|
|
1280
|
+
# Disable automatic update checks
|
|
1281
|
+
spamscanner scan email.eml --no-update-check
|
|
1282
|
+
```
|
|
1283
|
+
|
|
1284
|
+
To update to the latest version, simply re-run the installation command for your platform or use npm:
|
|
1285
|
+
|
|
1286
|
+
```bash
|
|
1287
|
+
# Update via npm
|
|
1288
|
+
npm update -g spamscanner
|
|
1289
|
+
|
|
1290
|
+
# Or re-download the binary (macOS/Linux)
|
|
1291
|
+
curl -fsSL https://github.com/spamscanner/spamscanner/releases/latest/download/spamscanner-$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m | sed 's/x86_64/x64/' | sed 's/aarch64/arm64/') -o /usr/local/bin/spamscanner
|
|
1292
|
+
chmod +x /usr/local/bin/spamscanner
|
|
1293
|
+
```
|
|
1294
|
+
|
|
1295
|
+
### Commands
|
|
1296
|
+
|
|
1297
|
+
| Command | Description |
|
|
1298
|
+
| ------------------------- | --------------------- |
|
|
1299
|
+
| `spamscanner scan <file>` | Scan an email file |
|
|
1300
|
+
| `spamscanner scan -` | Scan email from stdin |
|
|
1301
|
+
| `spamscanner server` | Start TCP server mode |
|
|
1302
|
+
| `spamscanner help` | Show help message |
|
|
1303
|
+
| `spamscanner version` | Show version number |
|
|
1304
|
+
| `spamscanner update` | Check for updates |
|
|
1305
|
+
|
|
1306
|
+
#### General Options
|
|
1307
|
+
|
|
1308
|
+
| Option | Description |
|
|
1309
|
+
| ------------------- | --------------------------------------------- |
|
|
1310
|
+
| `-h, --help` | Show help |
|
|
1311
|
+
| `-v, --version` | Show version |
|
|
1312
|
+
| `-j, --json` | Output results as JSON |
|
|
1313
|
+
| `--verbose` | Show detailed output |
|
|
1314
|
+
| `--debug` | Enable debug mode |
|
|
1315
|
+
| `--timeout <ms>` | Scan timeout in milliseconds (default: 30000) |
|
|
1316
|
+
| `--no-update-check` | Disable automatic update check |
|
|
1317
|
+
|
|
1318
|
+
#### Spam Detection Options
|
|
1319
|
+
|
|
1320
|
+
SpamScanner calculates a spam score based on multiple detection methods. You can configure which checks are included and customize the score weights.
|
|
1321
|
+
|
|
1322
|
+
| Option | Description |
|
|
1323
|
+
| --------------------- | ------------------------------------------------- |
|
|
1324
|
+
| `--threshold <score>` | Spam score threshold (default: 5.0) |
|
|
1325
|
+
| `--check-classifier` | Include Bayesian classifier in scoring (default) |
|
|
1326
|
+
| `--check-phishing` | Include phishing detection in scoring (default) |
|
|
1327
|
+
| `--check-executables` | Include executable detection in scoring (default) |
|
|
1328
|
+
| `--check-macros` | Include macro detection in scoring (default) |
|
|
1329
|
+
| `--check-virus` | Include virus detection in scoring (default) |
|
|
1330
|
+
| `--check-nsfw` | Include NSFW detection in scoring (disabled) |
|
|
1331
|
+
| `--check-toxicity` | Include toxicity detection in scoring (disabled) |
|
|
1332
|
+
| `--no-classifier` | Disable Bayesian classifier scoring |
|
|
1333
|
+
| `--no-phishing` | Disable phishing scoring |
|
|
1334
|
+
| `--no-executables` | Disable executable scoring |
|
|
1335
|
+
| `--no-macros` | Disable macro scoring |
|
|
1336
|
+
| `--no-virus` | Disable virus scoring |
|
|
1337
|
+
|
|
1338
|
+
#### Score Weights
|
|
1339
|
+
|
|
1340
|
+
Customize how much each detection type contributes to the total spam score:
|
|
1341
|
+
|
|
1342
|
+
| Option | Description |
|
|
1343
|
+
| ------------------------ | ------------------------------------------- |
|
|
1344
|
+
| `--score-classifier <n>` | Classifier spam score weight (default: 5.0) |
|
|
1345
|
+
| `--score-phishing <n>` | Phishing score per issue (default: 5.0) |
|
|
1346
|
+
| `--score-executable <n>` | Executable score per file (default: 10.0) |
|
|
1347
|
+
| `--score-macro <n>` | Macro score per detection (default: 5.0) |
|
|
1348
|
+
| `--score-virus <n>` | Virus score per detection (default: 100.0) |
|
|
1349
|
+
| `--score-nsfw <n>` | NSFW score per detection (default: 3.0) |
|
|
1350
|
+
| `--score-toxicity <n>` | Toxicity score per detection (default: 3.0) |
|
|
1351
|
+
|
|
1352
|
+
#### Header Options
|
|
1353
|
+
|
|
1354
|
+
For mail server integration, SpamScanner can add X-Spam headers to emails (similar to [SpamAssassin](https://github.com/apache/spamassassin) and [Stalwart](https://github.com/stalwartlabs/stalwart)):
|
|
1355
|
+
|
|
1356
|
+
| Option | Description |
|
|
1357
|
+
| --------------------- | ------------------------------------------ |
|
|
1358
|
+
| `--add-headers` | Add X-Spam-* headers to output |
|
|
1359
|
+
| `--prepend-subject` | Prepend [SPAM] to subject if spam detected |
|
|
1360
|
+
| `--subject-tag <tag>` | Custom subject tag (default: [SPAM]) |
|
|
1361
|
+
|
|
1362
|
+
**X-Spam Headers Added:**
|
|
1363
|
+
|
|
1364
|
+
| Header | Description |
|
|
1365
|
+
| --------------- | -------------------------------------------------------------------- |
|
|
1366
|
+
| `X-Spam-Status` | `Yes/No, score=X.X required=Y.Y tests=TEST1,TEST2,... version=X.X.X` |
|
|
1367
|
+
| `X-Spam-Score` | Numeric spam score (e.g., `7.5`) |
|
|
1368
|
+
| `X-Spam-Flag` | `YES` or `NO` |
|
|
1369
|
+
| `X-Spam-Tests` | Comma-separated list of triggered tests |
|
|
1370
|
+
|
|
1371
|
+
#### Scanner Configuration Options
|
|
1372
|
+
|
|
1373
|
+
These options configure the underlying SpamScanner engine:
|
|
1374
|
+
|
|
1375
|
+
| Option | Description |
|
|
1376
|
+
| -------------------------- | ------------------------------------------------------- |
|
|
1377
|
+
| `--languages <list>` | Comma-separated language codes (default: all languages) |
|
|
1378
|
+
| `--mixed-language` | Enable mixed language detection in emails |
|
|
1379
|
+
| `--no-macro-detection` | Disable macro detection in attachments |
|
|
1380
|
+
| `--no-pattern-recognition` | Disable advanced pattern recognition |
|
|
1381
|
+
| `--strict-idn` | Enable strict IDN/homograph detection |
|
|
1382
|
+
| `--nsfw-threshold <n>` | NSFW detection threshold 0.0-1.0 (default: 0.6) |
|
|
1383
|
+
| `--toxicity-threshold <n>` | Toxicity detection threshold 0.0-1.0 (default: 0.7) |
|
|
1384
|
+
| `--clamscan-path <path>` | Path to clamscan binary (default: /usr/bin/clamscan) |
|
|
1385
|
+
| `--clamdscan-path <path>` | Path to clamdscan binary (default: /usr/bin/clamdscan) |
|
|
1386
|
+
|
|
1387
|
+
##### Supported Languages
|
|
1388
|
+
|
|
1389
|
+
Use ISO 639-1 language codes with the `--languages` option. Pass an empty string or `all` to enable all languages (default).
|
|
1390
|
+
|
|
1391
|
+
| Code | Language | Code | Language | Code | Language |
|
|
1392
|
+
| ---- | --------------- | ---- | ---------- | ---- | ---------- |
|
|
1393
|
+
| `en` | English | `fr` | French | `es` | Spanish |
|
|
1394
|
+
| `de` | German | `it` | Italian | `pt` | Portuguese |
|
|
1395
|
+
| `ru` | Russian | `ja` | Japanese | `ko` | Korean |
|
|
1396
|
+
| `zh` | Chinese | `ar` | Arabic | `hi` | Hindi |
|
|
1397
|
+
| `bn` | Bengali | `ur` | Urdu | `tr` | Turkish |
|
|
1398
|
+
| `pl` | Polish | `nl` | Dutch | `sv` | Swedish |
|
|
1399
|
+
| `no` | Norwegian | `da` | Danish | `fi` | Finnish |
|
|
1400
|
+
| `hu` | Hungarian | `cs` | Czech | `sk` | Slovak |
|
|
1401
|
+
| `sl` | Slovenian | `hr` | Croatian | `sr` | Serbian |
|
|
1402
|
+
| `bg` | Bulgarian | `ro` | Romanian | `el` | Greek |
|
|
1403
|
+
| `he` | Hebrew | `th` | Thai | `vi` | Vietnamese |
|
|
1404
|
+
| `id` | Indonesian | `ms` | Malay | `tl` | Tagalog |
|
|
1405
|
+
| `uk` | Ukrainian | `be` | Belarusian | `lt` | Lithuanian |
|
|
1406
|
+
| `lv` | Latvian | `et` | Estonian | `ca` | Catalan |
|
|
1407
|
+
| `eu` | Basque | `gl` | Galician | `ga` | Irish |
|
|
1408
|
+
| `gd` | Scottish Gaelic | `cy` | Welsh | `is` | Icelandic |
|
|
1409
|
+
| `mt` | Maltese | `af` | Afrikaans | `sw` | Swahili |
|
|
1410
|
+
| `am` | Amharic | `ha` | Hausa | `yo` | Yoruba |
|
|
1411
|
+
| `ig` | Igbo | `so` | Somali | `om` | Oromo |
|
|
1412
|
+
| `ti` | Tigrinya | `mg` | Malagasy | `ny` | Chichewa |
|
|
1413
|
+
| `sn` | Shona | `xh` | Xhosa | `zu` | Zulu |
|
|
1414
|
+
| `st` | Southern Sotho | `tn` | Tswana | | |
|
|
1415
|
+
|
|
1416
|
+
#### Server Options
|
|
1417
|
+
|
|
1418
|
+
| Option | Description |
|
|
1419
|
+
| --------------- | ------------------------------------ |
|
|
1420
|
+
| `--port <port>` | TCP server port (default: 7830) |
|
|
1421
|
+
| `--host <host>` | TCP server host (default: 127.0.0.1) |
|
|
1422
|
+
|
|
1423
|
+
### Exit Codes
|
|
1424
|
+
|
|
1425
|
+
| Code | Meaning |
|
|
1426
|
+
| ---- | ---------------- |
|
|
1427
|
+
| `0` | Clean (not spam) |
|
|
1428
|
+
| `1` | Spam detected |
|
|
1429
|
+
| `2` | Error occurred |
|
|
1430
|
+
|
|
1431
|
+
### CLI Examples
|
|
1432
|
+
|
|
1433
|
+
```bash
|
|
1434
|
+
# Scan a file
|
|
1435
|
+
spamscanner scan email.eml
|
|
1436
|
+
|
|
1437
|
+
# Scan from stdin (for Postfix integration)
|
|
1438
|
+
cat email.eml | spamscanner scan -
|
|
1439
|
+
|
|
1440
|
+
# Scan with JSON output (includes score and tests)
|
|
1441
|
+
spamscanner scan email.eml --json
|
|
1442
|
+
|
|
1443
|
+
# Scan with verbose output
|
|
1444
|
+
spamscanner scan email.eml --verbose
|
|
1445
|
+
|
|
1446
|
+
# Scan with custom spam threshold
|
|
1447
|
+
spamscanner scan email.eml --threshold 3.0
|
|
1448
|
+
|
|
1449
|
+
# Scan with only classifier and phishing checks
|
|
1450
|
+
spamscanner scan email.eml --no-executables --no-macros --no-virus
|
|
1451
|
+
|
|
1452
|
+
# Scan and add X-Spam headers (for mail server integration)
|
|
1453
|
+
spamscanner scan email.eml --add-headers
|
|
1454
|
+
|
|
1455
|
+
# Scan, add headers, and prepend [SPAM] to subject
|
|
1456
|
+
spamscanner scan email.eml --add-headers --prepend-subject
|
|
1457
|
+
|
|
1458
|
+
# Scan with custom subject tag
|
|
1459
|
+
spamscanner scan email.eml --add-headers --prepend-subject --subject-tag "[JUNK]"
|
|
1460
|
+
|
|
1461
|
+
# Enable NSFW and toxicity checks with custom weights
|
|
1462
|
+
spamscanner scan email.eml --check-nsfw --check-toxicity --score-nsfw 5.0
|
|
1463
|
+
|
|
1464
|
+
# Start TCP server on custom port
|
|
1465
|
+
spamscanner server --port 8080
|
|
1466
|
+
|
|
1467
|
+
# Start TCP server with custom threshold
|
|
1468
|
+
spamscanner server --port 8080 --threshold 3.0
|
|
1469
|
+
|
|
1470
|
+
# Scan with specific language support (English, Spanish, French only)
|
|
1471
|
+
spamscanner scan email.eml --languages en,es,fr
|
|
1472
|
+
|
|
1473
|
+
# Scan with mixed language detection enabled
|
|
1474
|
+
spamscanner scan email.eml --mixed-language
|
|
1475
|
+
|
|
1476
|
+
# Scan with strict IDN/homograph detection
|
|
1477
|
+
spamscanner scan email.eml --strict-idn
|
|
1478
|
+
|
|
1479
|
+
# Scan with custom NSFW threshold (more sensitive)
|
|
1480
|
+
spamscanner scan email.eml --check-nsfw --nsfw-threshold 0.3
|
|
1481
|
+
|
|
1482
|
+
# Scan with custom ClamAV paths
|
|
1483
|
+
spamscanner scan email.eml --clamscan-path /opt/clamav/bin/clamscan
|
|
1484
|
+
```
|
|
1485
|
+
|
|
1486
|
+
#### Example JSON Output
|
|
1487
|
+
|
|
1488
|
+
```json
|
|
1489
|
+
{
|
|
1490
|
+
"isSpam": true,
|
|
1491
|
+
"score": 7.5,
|
|
1492
|
+
"threshold": 5.0,
|
|
1493
|
+
"tests": ["BAYES_SPAM(5.0)", "PHISHING_DETECTED(2.5)"],
|
|
1494
|
+
"message": "Spam",
|
|
1495
|
+
"results": {
|
|
1496
|
+
"classification": { "category": "spam", "probability": 0.95 },
|
|
1497
|
+
"phishing": [{ "type": "suspicious_link", "url": "http://example.com" }]
|
|
1498
|
+
},
|
|
1499
|
+
"headers": {
|
|
1500
|
+
"X-Spam-Status": "Yes, score=7.5 required=5.0 tests=BAYES_SPAM(5.0),PHISHING_DETECTED(2.5) version=6.0.1",
|
|
1501
|
+
"X-Spam-Score": "7.5",
|
|
1502
|
+
"X-Spam-Flag": "YES",
|
|
1503
|
+
"X-Spam-Tests": "BAYES_SPAM(5.0), PHISHING_DETECTED(2.5)"
|
|
1504
|
+
}
|
|
1505
|
+
}
|
|
1506
|
+
```
|
|
1507
|
+
|
|
1508
|
+
---
|
|
1509
|
+
|
|
1510
|
+
|
|
1511
|
+
## ARF (Abuse Reporting Format)
|
|
1512
|
+
|
|
1513
|
+
SpamScanner includes a native [ARF (Abuse Reporting Format)](https://www.rfc-editor.org/rfc/rfc5965.html) parser for handling email feedback reports from ISPs and email providers.
|
|
1514
|
+
|
|
1515
|
+
### Parsing ARF Reports
|
|
1516
|
+
|
|
1517
|
+
```js
|
|
1518
|
+
import {ArfParser} from 'spamscanner/arf';
|
|
1519
|
+
import fs from 'node:fs';
|
|
1520
|
+
|
|
1521
|
+
// Read an ARF report email
|
|
1522
|
+
const arfEmail = fs.readFileSync('feedback_report.eml');
|
|
1523
|
+
|
|
1524
|
+
// Parse the ARF report
|
|
1525
|
+
const report = await ArfParser.parse(arfEmail);
|
|
1526
|
+
|
|
1527
|
+
console.log('Feedback Type:', report.feedbackType);
|
|
1528
|
+
console.log('Source IP:', report.sourceIp);
|
|
1529
|
+
console.log('Original Sender:', report.originalMailFrom);
|
|
1530
|
+
console.log('Original Recipients:', report.originalRcptTo);
|
|
1531
|
+
```
|
|
1532
|
+
|
|
1533
|
+
#### Safe Parsing
|
|
1534
|
+
|
|
1535
|
+
```js
|
|
1536
|
+
// Use tryParse for safe parsing (returns null if not ARF)
|
|
1537
|
+
const report = await ArfParser.tryParse(emailContent);
|
|
1538
|
+
|
|
1539
|
+
if (report) {
|
|
1540
|
+
console.log('ARF report detected:', report.feedbackType);
|
|
1541
|
+
} else {
|
|
1542
|
+
console.log('Not an ARF report');
|
|
1543
|
+
}
|
|
1544
|
+
```
|
|
1545
|
+
|
|
1546
|
+
### Creating ARF Reports
|
|
1547
|
+
|
|
1548
|
+
```js
|
|
1549
|
+
import {ArfParser} from 'spamscanner/arf';
|
|
1550
|
+
|
|
1551
|
+
const arfMessage = ArfParser.create({
|
|
1552
|
+
feedbackType: 'abuse',
|
|
1553
|
+
userAgent: 'MyMailServer/1.0',
|
|
1554
|
+
from: 'abuse@yourdomain.com',
|
|
1555
|
+
to: 'abuse@theirisp.com',
|
|
1556
|
+
originalMessage: originalEmailContent,
|
|
1557
|
+
humanReadable: 'This email was reported as spam by our users.',
|
|
1558
|
+
sourceIp: '192.168.1.100',
|
|
1559
|
+
originalMailFrom: 'spammer@example.com',
|
|
1560
|
+
originalRcptTo: ['victim@yourdomain.com'],
|
|
1561
|
+
arrivalDate: new Date(),
|
|
1562
|
+
reportingMta: 'mail.yourdomain.com',
|
|
1563
|
+
});
|
|
1564
|
+
|
|
1565
|
+
// Send arfMessage to the abuse address
|
|
1566
|
+
```
|
|
1567
|
+
|
|
1568
|
+
### ARF Result Object
|
|
1569
|
+
|
|
1570
|
+
| Property | Type | Description |
|
|
1571
|
+
| ------------------ | ---------- | ----------------------------------------------------------------------------- |
|
|
1572
|
+
| `isArf` | `boolean` | Whether this is a valid ARF message |
|
|
1573
|
+
| `feedbackType` | `string` | Type: `abuse`, `fraud`, `virus`, `other`, `not-spam`, `auth-failure`, `dmarc` |
|
|
1574
|
+
| `userAgent` | `string` | User agent that generated the report |
|
|
1575
|
+
| `version` | `string` | ARF version (usually "1") |
|
|
1576
|
+
| `sourceIp` | `string` | Source IP of the original message |
|
|
1577
|
+
| `originalMailFrom` | `string` | Original MAIL FROM address |
|
|
1578
|
+
| `originalRcptTo` | `string[]` | Original RCPT TO addresses |
|
|
1579
|
+
| `arrivalDate` | `Date` | When the original message arrived |
|
|
1580
|
+
| `reportingMta` | `object` | Reporting MTA info (`{type, name}`) |
|
|
1581
|
+
| `incidents` | `number` | Number of incidents reported |
|
|
1582
|
+
| `humanReadable` | `string` | Human-readable description |
|
|
1583
|
+
| `originalMessage` | `string` | The original reported message |
|
|
1584
|
+
| `originalHeaders` | `object` | Parsed headers from original message |
|
|
1585
|
+
|
|
1586
|
+
---
|
|
1587
|
+
|
|
1588
|
+
|
|
1589
|
+
## Mail Server Integration
|
|
1590
|
+
|
|
1591
|
+
SpamScanner can be integrated with popular mail servers like [Postfix](https://www.postfix.org/) and [Dovecot](https://www.dovecot.org/) as a content filter.
|
|
1592
|
+
|
|
1593
|
+
### Postfix Integration
|
|
1594
|
+
|
|
1595
|
+
#### Using Pipe Content Filter
|
|
1596
|
+
|
|
1597
|
+
This is the recommended method for most Postfix setups.
|
|
1598
|
+
|
|
1599
|
+
1. **Create a dedicated user** (recommended for security):
|
|
1600
|
+
|
|
1601
|
+
```bash
|
|
1602
|
+
sudo useradd -r -s /bin/false spamscanner
|
|
1603
|
+
```
|
|
1604
|
+
|
|
1605
|
+
2. **Edit `/etc/postfix/master.cf`**:
|
|
1606
|
+
|
|
1607
|
+
```cf
|
|
1608
|
+
# SpamScanner content filter
|
|
1609
|
+
spamscanner unix - n n - - pipe
|
|
1610
|
+
flags=Rq user=spamscanner argv=/usr/local/bin/spamscanner scan -
|
|
1611
|
+
```
|
|
1612
|
+
|
|
1613
|
+
3. **Edit `/etc/postfix/main.cf`**:
|
|
1614
|
+
|
|
1615
|
+
```cf
|
|
1616
|
+
content_filter = spamscanner:dummy
|
|
1617
|
+
```
|
|
1618
|
+
|
|
1619
|
+
4. **Reload Postfix**:
|
|
1620
|
+
|
|
1621
|
+
```bash
|
|
1622
|
+
sudo postfix reload
|
|
1623
|
+
```
|
|
1624
|
+
|
|
1625
|
+
Postfix will now pipe all incoming emails to SpamScanner. If SpamScanner exits with code 1 (spam), Postfix will reject the message.
|
|
1626
|
+
|
|
1627
|
+
### Dovecot Integration
|
|
1628
|
+
|
|
1629
|
+
#### Using Sieve and Pipe
|
|
1630
|
+
|
|
1631
|
+
1. **Enable Pigeonhole Sieve** (ensure `dovecot-pigeonhole` is installed)
|
|
1632
|
+
|
|
1633
|
+
2. **Create a Sieve script** (`/var/lib/dovecot/sieve/default.sieve`):
|
|
1634
|
+
|
|
1635
|
+
```sieve
|
|
1636
|
+
require ["vnd.dovecot.pipe"];
|
|
1637
|
+
|
|
1638
|
+
# Scan all incoming mail
|
|
1639
|
+
if header :contains "X-Spam-Flag" "NO" {
|
|
1640
|
+
pipe "/usr/local/bin/spamscanner-sieve-helper";
|
|
1641
|
+
}
|
|
1642
|
+
```
|
|
1643
|
+
|
|
1644
|
+
3. **Create a helper script** (`/usr/local/bin/spamscanner-sieve-helper`):
|
|
1645
|
+
|
|
1646
|
+
```bash
|
|
1647
|
+
#!/bin/bash
|
|
1648
|
+
EMAIL=$(cat)
|
|
1649
|
+
RESULT=$(echo "$EMAIL" | /usr/local/bin/spamscanner scan -)
|
|
1650
|
+
if [[ $? -eq 1 ]]; then
|
|
1651
|
+
echo "X-Spam-Flag: YES" | cat - <(echo "$EMAIL")
|
|
1652
|
+
else
|
|
1653
|
+
echo "$EMAIL"
|
|
1654
|
+
fi
|
|
1655
|
+
```
|
|
1656
|
+
|
|
1657
|
+
### TCP Server Mode
|
|
1658
|
+
|
|
1659
|
+
For high-volume environments, run SpamScanner as a persistent TCP server:
|
|
1660
|
+
|
|
1661
|
+
```bash
|
|
1662
|
+
# Start the server
|
|
1663
|
+
spamscanner server --port 7830 --host 127.0.0.1
|
|
1664
|
+
```
|
|
1665
|
+
|
|
1666
|
+
#### Systemd Service
|
|
1667
|
+
|
|
1668
|
+
Create `/etc/systemd/system/spamscanner.service`:
|
|
1669
|
+
|
|
1670
|
+
```ini
|
|
1671
|
+
[Unit]
|
|
1672
|
+
Description=SpamScanner TCP Server
|
|
1673
|
+
After=network.target
|
|
1674
|
+
|
|
1675
|
+
[Service]
|
|
1676
|
+
Type=simple
|
|
1677
|
+
User=spamscanner
|
|
1678
|
+
ExecStart=/usr/local/bin/spamscanner server --port 7830
|
|
1679
|
+
Restart=always
|
|
1680
|
+
RestartSec=5
|
|
1681
|
+
|
|
1682
|
+
[Install]
|
|
1683
|
+
WantedBy=multi-user.target
|
|
1684
|
+
```
|
|
1685
|
+
|
|
1686
|
+
Enable and start:
|
|
1687
|
+
|
|
1688
|
+
```bash
|
|
1689
|
+
sudo systemctl enable spamscanner
|
|
1690
|
+
sudo systemctl start spamscanner
|
|
1691
|
+
```
|
|
1692
|
+
|
|
1693
|
+
#### Client Example
|
|
1694
|
+
|
|
1695
|
+
```bash
|
|
1696
|
+
# Send email to TCP server and get JSON response
|
|
1697
|
+
cat email.eml | nc localhost 7830
|
|
1698
|
+
```
|
|
1699
|
+
|
|
1700
|
+
---
|
|
1701
|
+
|
|
1702
|
+
|
|
1181
1703
|
## Performance
|
|
1182
1704
|
|
|
1183
1705
|
### Benchmarks
|
|
@@ -1276,3 +1798,8 @@ npm run test-coverage
|
|
|
1276
1798
|
---
|
|
1277
1799
|
|
|
1278
1800
|
> Made with ❤️ by the [Forward Email](https://forwardemail.net) team
|
|
1801
|
+
|
|
1802
|
+
|
|
1803
|
+
##
|
|
1804
|
+
|
|
1805
|
+
<a href="#"><img src="https://raw.githubusercontent.com/spamscanner/spamscanner/master/media/footer.png" alt="#" /></a>
|