spamscanner 6.0.1 → 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 CHANGED
@@ -66,6 +66,19 @@
66
66
  * [Selective Feature Disabling](#selective-feature-disabling)
67
67
  * [Custom Timeout](#custom-timeout)
68
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)
69
82
  * [Performance](#performance)
70
83
  * [Benchmarks](#benchmarks)
71
84
  * [Optimization Tips](#optimization-tips)
@@ -1185,6 +1198,508 @@ const scanner = new SpamScanner({
1185
1198
  ---
1186
1199
 
1187
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
+
1188
1703
  ## Performance
1189
1704
 
1190
1705
  ### Benchmarks