From 766bf554840207366089c956423a3c76500b7506 Mon Sep 17 00:00:00 2001 From: Dick Tump Date: Tue, 21 Jul 2026 09:03:23 +0200 Subject: [PATCH 1/2] Add anonymised spam benchmark corpus --- .gitattributes | 2 + .gitignore | 3 + AGENTS.md | 17 +- README.md | 50 +- config.ini.default | 4 +- pyproject.toml | 3 + tests/fixtures/spam/README.md | 39 + .../advance_fee_confidential_transaction.eml | 122 ++++ .../spam/advance_fee_fake_donation.eml | 46 ++ .../spam/advance_fee_fake_police_notice.eml | 72 ++ .../spam/advance_fee_fintrac_funds.eml | 50 ++ .../spam/advance_fee_lottery_winner.eml | 222 ++++++ .../spam/phishing_benu_security_update.eml | 361 ++++++++++ .../spam/phishing_bitvavo_address_check.eml | 651 +++++++++++++++++ .../spam/phishing_cloud_storage_payment.eml | 293 ++++++++ .../spam/phishing_cloud_storage_renewal.eml | 154 ++++ .../fixtures/spam/phishing_coinmerce_mica.eml | 535 ++++++++++++++ .../spam/phishing_fake_card_transaction.eml | 370 ++++++++++ .../fixtures/spam/phishing_fake_cjib_fine.eml | 573 +++++++++++++++ .../spam/phishing_fake_coinbase_deposit.eml | 21 + .../spam/phishing_fake_document_signature.eml | 50 ++ .../spam/phishing_fake_domain_termination.eml | 674 ++++++++++++++++++ .../spam/phishing_fake_rvo_subsidy.eml | 275 +++++++ .../fixtures/spam/phishing_icloud_billing.eml | 101 +++ .../spam/phishing_raiffeisen_pushtan.eml | 310 ++++++++ .../spam_wordpress_credential_injection.eml | 18 + .../spam/unsolicited_prescription_drugs.eml | 10 + tests/test_spam_corpus.py | 70 ++ tests/test_spam_corpus_live.py | 62 ++ 29 files changed, 5153 insertions(+), 5 deletions(-) create mode 100644 .gitattributes create mode 100644 tests/fixtures/spam/README.md create mode 100644 tests/fixtures/spam/advance_fee_confidential_transaction.eml create mode 100644 tests/fixtures/spam/advance_fee_fake_donation.eml create mode 100644 tests/fixtures/spam/advance_fee_fake_police_notice.eml create mode 100644 tests/fixtures/spam/advance_fee_fintrac_funds.eml create mode 100644 tests/fixtures/spam/advance_fee_lottery_winner.eml create mode 100644 tests/fixtures/spam/phishing_benu_security_update.eml create mode 100644 tests/fixtures/spam/phishing_bitvavo_address_check.eml create mode 100644 tests/fixtures/spam/phishing_cloud_storage_payment.eml create mode 100644 tests/fixtures/spam/phishing_cloud_storage_renewal.eml create mode 100644 tests/fixtures/spam/phishing_coinmerce_mica.eml create mode 100644 tests/fixtures/spam/phishing_fake_card_transaction.eml create mode 100644 tests/fixtures/spam/phishing_fake_cjib_fine.eml create mode 100644 tests/fixtures/spam/phishing_fake_coinbase_deposit.eml create mode 100644 tests/fixtures/spam/phishing_fake_document_signature.eml create mode 100644 tests/fixtures/spam/phishing_fake_domain_termination.eml create mode 100644 tests/fixtures/spam/phishing_fake_rvo_subsidy.eml create mode 100644 tests/fixtures/spam/phishing_icloud_billing.eml create mode 100644 tests/fixtures/spam/phishing_raiffeisen_pushtan.eml create mode 100644 tests/fixtures/spam/spam_wordpress_credential_injection.eml create mode 100644 tests/fixtures/spam/unsolicited_prescription_drugs.eml create mode 100644 tests/test_spam_corpus.py create mode 100644 tests/test_spam_corpus_live.py diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..c1bf22f --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Raw email fixtures legitimately contain quoted-printable whitespace. +tests/fixtures/spam/*.eml -whitespace diff --git a/.gitignore b/.gitignore index 9dfb0ab..d56f1b5 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,6 @@ build/ # Virtual environments .venv/ venv/ + +# Local raw mail (never commit) +/spam/ diff --git a/AGENTS.md b/AGENTS.md index addac29..d49e294 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -47,11 +47,24 @@ pip install -e ".[dev]" ## Testing - **Framework**: pytest 9.0.3 -- **Run tests**: `pytest -v` -- **All changes must pass**: `ruff check . && ruff format --check . && pytest` +- **Run tests**: `.venv/bin/pytest -v` (or activate `.venv` first) +- **All changes must pass**: `.venv/bin/ruff check . && .venv/bin/ruff format --check . && .venv/bin/pytest` - Tests live in `tests/` and mirror the module structure - Mock external APIs โ€” never make real API calls in tests. Use `unittest.mock.patch` for API clients and `monkeypatch` for config paths - Use `tmp_path` for temporary files, `monkeypatch` for config isolation +- `tests/fixtures/spam/` contains a reviewed corpus of 20 anonymised, distinct spam campaigns. + Use it for parser/formatting regression tests, and extend it only with clearly spam, non-duplicate + messages. +- Fixture privacy is mandatory: remove delivery/authentication/`X-` headers and attachments, and + redact all recipient, organisation, domain, mail-server, and other identifying information from + decoded headers and text/HTML MIME parts. Keep the corpus privacy tests passing. +- `tests/test_spam_corpus_live.py` is an opt-in LLM benchmark. It is skipped unless + `INSPAMITY_RUN_LIVE_LLM=1`; it must never make provider calls in ordinary tests or CI. A developer + with a private configured API key can run one fixture with + `INSPAMITY_RUN_LIVE_LLM=1 .venv/bin/pytest -m live_llm -v --durations=1 --log-cli-level=INFO`. + This logs each LLM result (classification, confidence, reason, and duration). Increase + `INSPAMITY_LIVE_LLM_FIXTURE_COUNT` (up to 20) for a more representative run. The local + `config.ini` needs only `settings.provider`, and the selected provider's `api_key` and `model`. ## Architecture Notes diff --git a/README.md b/README.md index 15db05f..d6fcdb9 100644 --- a/README.md +++ b/README.md @@ -125,7 +125,8 @@ timeout = 20.0 [openai] api_key = your_api_key_here model = gpt-5.6-luna -temperature = 0.0 +# GPT-5-class models do not support temperature; leave it unset for those models. +# temperature = 0.0 timeout = 20.0 ``` @@ -156,6 +157,53 @@ You can adjust these settings by editing the installed plugin at `/etc/rspamd/pl 4. Based on the response, rspamd adjusts the spam score accordingly 5. Detailed logging provides insights into the decision-making process +## ๐Ÿงช Testing and spam corpus + +The regular test suite includes an anonymised, reviewed corpus of 20 distinct +spam campaigns in `tests/fixtures/spam/`. It exercises email parsing and +formatting without calling an LLM, and verifies that recipient and mail-server +identifiers are not present in the committed fixtures: + +```bash +.venv/bin/pytest -v +``` + +For an opt-in local OpenAI benchmark, create the ignored `config.ini` in the +project root with only these required settings: + +```ini +[settings] +provider = openai + +[openai] +api_key = your_api_key_here +model = your_model_id +``` + +`timeout` and `temperature` are optional; the benchmark needs neither. The +project's `config.ini` is ignored by Git, and `/etc/inspamity/config.ini`, when +present, takes precedence over it. + +Run one fixture by default: + +```bash +INSPAMITY_RUN_LIVE_LLM=1 .venv/bin/pytest -m live_llm -v --durations=1 --log-cli-level=INFO +``` + +`--durations=1` only reports the single slowest test; it does not control the +number of API calls. `--log-cli-level=INFO` displays one line per LLM response +with its spam classification, confidence, reason, and duration. The default +benchmark makes one API call. For a more representative run, increase the +number of corpus fixtures (up to 20), for example: + +```bash +INSPAMITY_RUN_LIVE_LLM=1 INSPAMITY_LIVE_LLM_FIXTURE_COUNT=20 \ + .venv/bin/pytest -m live_llm -v --durations=20 --log-cli-level=INFO +``` + +The live tests expect every reviewed fixture to be classified as spam. They are +skipped unless `INSPAMITY_RUN_LIVE_LLM=1` is set, so they never run in CI. + ## ๐Ÿ› Troubleshooting - Check rspamd logs for errors: `sudo tail -f /var/log/rspamd/rspamd.log` diff --git a/config.ini.default b/config.ini.default index cacfe1a..d9541dd 100644 --- a/config.ini.default +++ b/config.ini.default @@ -21,6 +21,6 @@ timeout = 20.0 [openai] api_key = your_api_key_here model = gpt-5.6-luna -# Temperature for AI responses (0.0 = deterministic). Remove to use model default. -temperature = 0.0 +# GPT-5-class models do not support temperature; leave it unset for those models. +# temperature = 0.0 timeout = 20.0 diff --git a/pyproject.toml b/pyproject.toml index 9c16846..d3a71ff 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -30,6 +30,9 @@ include = ["email_utils*"] [tool.pytest.ini_options] testpaths = ["tests"] +markers = [ + "live_llm: tests that call a configured external LLM provider (opt-in only)", +] [tool.ruff] target-version = "py310" diff --git a/tests/fixtures/spam/README.md b/tests/fixtures/spam/README.md new file mode 100644 index 0000000..1d923ad --- /dev/null +++ b/tests/fixtures/spam/README.md @@ -0,0 +1,39 @@ +# Anonymised spam corpus + +This directory contains 20 reviewed spam messages from July 2026. It is a +small, intentionally varied regression corpus for email parsing and optional +local LLM benchmarking; every fixture's expected classification is **spam**. + +The source messages were selected as single representatives of their campaign. +Near-identical deliveries (including messages differing only in recipient, +transport headers, timestamps, or tracking identifiers) were excluded. + +All recipient and mail-server data was removed before committing the fixtures: + +- transport, authentication, delivery, and `X-` headers were discarded; +- binary attachments were discarded; +- recipient addresses, domains, names, and server IP addresses were replaced + in decoded headers and text/HTML MIME parts. + +| Fixture | Review rationale | +| --- | --- | +| `advance_fee_confidential_transaction.eml` | Vague lucrative confidential-transaction offer to undisclosed recipients. | +| `advance_fee_fake_donation.eml` | Unsolicited EUR 4.5 million donation with a generic reply address. | +| `advance_fee_fake_police_notice.eml` | Impersonates police/Europol to solicit a response. | +| `advance_fee_fintrac_funds.eml` | FINTRAC-held-funds impersonation with an unrelated sender/reply address. | +| `advance_fee_lottery_winner.eml` | Unsolicited lottery award and direct reply request. | +| `phishing_benu_security_update.eml` | BENU security impersonation from an unrelated domain. | +| `phishing_bitvavo_address_check.eml` | Bitvavo lookalike domain requesting an address check. | +| `phishing_cloud_storage_payment.eml` | Generic cloud-payment suspension threat with unrelated links. | +| `phishing_cloud_storage_renewal.eml` | Fake cloud-renewal expiry threat from an unrelated domain. | +| `phishing_coinmerce_mica.eml` | Coinmerce/MiCA verification lure pointing to an unrelated target. | +| `phishing_fake_card_transaction.eml` | Fake card transaction/security-alert social engineering. | +| `phishing_fake_cjib_fine.eml` | CJIB fine impersonation with unrelated sender and payment link. | +| `phishing_fake_coinbase_deposit.eml` | Unsolicited 18 BTC deposit notification with unrelated link. | +| `phishing_fake_document_signature.eml` | Urgent document-signature impersonation. | +| `phishing_fake_domain_termination.eml` | Fake domain termination/renewal notice. | +| `phishing_fake_rvo_subsidy.eml` | RVO subsidy lure from an unrelated sender. | +| `phishing_icloud_billing.eml` | Fake iCloud billing suspension with a short action deadline. | +| `phishing_raiffeisen_pushtan.eml` | Raiffeisen pushTAN impersonation with unrelated links. | +| `spam_wordpress_credential_injection.eml` | WordPress login message whose credentials contain crypto bait. | +| `unsolicited_prescription_drugs.eml` | Unsolicited prescription-drug sales link. | diff --git a/tests/fixtures/spam/advance_fee_confidential_transaction.eml b/tests/fixtures/spam/advance_fee_confidential_transaction.eml new file mode 100644 index 0000000..f763ff6 --- /dev/null +++ b/tests/fixtures/spam/advance_fee_confidential_transaction.eml @@ -0,0 +1,122 @@ +MIME-Version: 1.0 +Reply-To: dawsondaniel1133@gmail.com +From: dawsondanie <07898@srp2.ac.th> +Date: Sat, 11 Jul 2026 15:32:10 +0530 +Message-ID: + +Subject: Hello, +To: undisclosed-recipients:; +Content-Type: multipart/alternative; boundary="00000000000019b4cf065652f45a" + +--00000000000019b4cf065652f45a +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: quoted-printable +MIME-Version: 1.0 + + *Hello,* + +*I would like to discuss a confidential and legitimate transaction +opportunity with you that has the potential to be financially rewarding for +both of us. I believe this proposal could lead to a mutually beneficial +partnership, and I would appreciate the opportunity to share the details +with you.* + +*If this is of interest, please reply at your earliest convenience, and I +will provide you with more information.* + +*I look forward to hearing from you.* + +*Best regards,* +Dawson Daniel +My email id: dawsondaniel1133@gmail.com + + - + +--00000000000019b4cf065652f45a +Content-Type: text/html; charset="utf-8" +Content-Transfer-Encoding: quoted-printable +MIME-Version: 1.0 + +
+
+
+
Hello,
+
=C2= +=A0
+
I would like to discuss a confidential and legitimate=20 +transaction opportunity with you that has the potential to be=20 +financially rewarding for both of us. I believe this proposal could lead + to a mutually beneficial partnership, and I would appreciate the=20 +opportunity to share the details with you.
+
=C2= +=A0
+
If this is of interest, please reply at your earliest convenience, and I will provid= +e you with more information.
+
=C2= +=A0
+
I look forward to hearing from you.
+
=C2= +=A0
+
Best regards,
+Dawson Daniel + +
+
+
+My email id: dawsondaniel1133@gmail.com + +
+
<= +/div>
+ +
+ +--00000000000019b4cf065652f45a-- diff --git a/tests/fixtures/spam/advance_fee_fake_donation.eml b/tests/fixtures/spam/advance_fee_fake_donation.eml new file mode 100644 index 0000000..2c8638e --- /dev/null +++ b/tests/fixtures/spam/advance_fee_fake_donation.eml @@ -0,0 +1,46 @@ +DKIM-Filter: OpenDKIM Filter v2.10.3 zimbra.efbet.com 6547818BBCC4 +Date: Sat, 04 Jul 2026 22:01:24 +0000 +From: "Ms. Schaeffler" +Reply-To: "Ms. Schaeffler" +Message-ID: <649954923.17839641.1783202484535.JavaMail.zimbra@efbet.com> +Subject: AMN: Gefeliciteerd! +MIME-Version: 1.0 +Content-Type: multipart/alternative; + boundary="=_373fc15c-dfbe-42ed-83b2-303e61988f67" +Thread-Index: ORys/megSyCRN8BJ6IwvQ6z6jMQIWQ== +Thread-Topic: Gefeliciteerd! + +--=_373fc15c-dfbe-42ed-83b2-303e61988f67 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: quoted-printable +MIME-Version: 1.0 + + + +Gefeliciteerd!=20 + +Uw e-mailadres is willekeurig geselecteerd en u ontvangt een donatie van =E2= +=82=AC 4.500.000,00. Neem voor meer informatie contact met ons op via onderst= +aand e-mailadres.=20 + +Neem uitsluitend contact met ons op via onderstaand e-mailadres.=20 + +E-mail: gmbhschaefflerag@gmail.com=20 + +Schaeffler GMBH=20 + +--=_373fc15c-dfbe-42ed-83b2-303e61988f67 +Content-Type: text/html; charset="utf-8" +Content-Transfer-Encoding: quoted-printable +MIME-Version: 1.0 + +


Gefeliciteerd!

Uw e-mailadres is willekeurig geselecteerd e= +n u ontvangt een donatie van =E2=82=AC 4.500.000,00. Neem voor meer informati= +e contact met ons op via onderstaand e-mailadres.

Neem uitsluitend con= +tact met ons op via onderstaand e-mailadres.

E-mail: gmbhschaefflerag@= +gmail.com

Schaeffler GMBH
+ +--=_373fc15c-dfbe-42ed-83b2-303e61988f67-- + diff --git a/tests/fixtures/spam/advance_fee_fake_police_notice.eml b/tests/fixtures/spam/advance_fee_fake_police_notice.eml new file mode 100644 index 0000000..cf2a46c --- /dev/null +++ b/tests/fixtures/spam/advance_fee_fake_police_notice.eml @@ -0,0 +1,72 @@ +DKIM-Filter: OpenDKIM Filter v2.10.3 fut003.vmail.ae BEB80C2E9B19 +Date: Wed, 08 Jul 2026 09:44:45 +0400 +From: Korpschef JANNY KNOL +Reply-To: korpschef.politienationale@myyahoo.com +To: + korpschef politienationale +Message-ID: <972278551.1311896.1783489485764.JavaMail.zimbra@gltg.ae> +Subject: =?utf-8?q?OFFICI=C3=8BLE?= OPROEP: FEDERALE POLITIE ZAAK #500-2025-NL +MIME-Version: 1.0 +Content-Type: multipart/mixed; + boundary="----=_Part_1311889_2567609.1783489485757" +Thread-Index: QvVSe0ajd0YRDpnz1jhMFAztma+XAg== +Thread-Topic: =?utf-8?q?OFFICI=C3=8BLE?= OPROEP: FEDERALE POLITIE ZAAK + #500-2025-NL + +------=_Part_1311889_2567609.1783489485757 +Content-Type: multipart/alternative; + boundary="=_757ed727-7b29-49b8-94aa-fbcd86facea1" + +--=_757ed727-7b29-49b8-94aa-fbcd86facea1 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: quoted-printable +MIME-Version: 1.0 + +Geachte,=20 +Hierbij delen wij u mee dat er een offici=C3=ABle klacht tegen u is ingediend= + in het kader van een gezamenlijk onderzoek met de diensten van de Europese P= +olitie (Europol).=20 +Het exacte onderwerp van deze klacht vereist uw dringende opheldering.=20 +U bent verplicht onmiddellijk contact op te nemen met de aangewezen onderzoek= +sdienst door te reageren op dit e-mailadres: korpschef.politienationale@myyah= +oo.com=20 +Gelieve deze kennisgeving als een wettelijke waarschuwing te beschouwen en de= +ze niet te negeren.=20 +Hoogachtend,=20 +De Afdeling Juridische Zaken en Cyberbeveiliging (Onder gezag van Europol)=20 + +BELANGRIJK: Technische instructie Indien dit bericht in uw ongewenste e-mail = +(spam) is terechtgekomen, dient u het onmiddellijk te markeren als "geen spam= +" en te verplaatsen naar uw inbox. Dit is noodzakelijk om de bijgevoegde docu= +menten correct te kunnen lezen en verdere blokkades door uw provider te voork= +omen. Het niet tijdig openen van dit dossier door technische filters ontslaat= + u niet van uw antwoordplicht binnen 72 uur.=20 + + +--=_757ed727-7b29-49b8-94aa-fbcd86facea1 +Content-Type: text/html; charset="utf-8" +Content-Transfer-Encoding: quoted-printable +MIME-Version: 1.0 + +
<= +div>=C2=A0Geachte,
Hierbij delen wij u mee dat er een offici=C3=ABle klach= +t tegen u is ingediend in het kader van een gezamenlijk onderzoek met de dien= +sten van de Europese Politie (Europol).
Het exacte onderwerp van deze klac= +ht vereist uw dringende opheldering.
U bent verplicht onmiddellijk contact= + op te nemen met de aangewezen onderzoeksdienst door te reageren op dit e-mai= +ladres: korpschef.politienationale@myyahoo.com
Gelieve deze kennisgeving a= +ls een wettelijke waarschuwing te beschouwen en deze niet te negeren.
Hoog= +achtend,
De Afdeling Juridische Zaken en Cyberbeveiliging (Onder gezag van= + Europol)
=C2=A0
BELANGRIJK: Technische instructie Indien dit bericht i= +n uw ongewenste e-mail (spam) is terechtgekomen, dient u het onmiddellijk te = +markeren als "geen spam" en te verplaatsen naar uw inbox. Dit is noodzakelijk= + om de bijgevoegde documenten correct te kunnen lezen en verdere blokkades do= +or uw provider te voorkomen. Het niet tijdig openen van dit dossier door tech= +nische filters ontslaat u niet van uw antwoordplicht binnen 72 uur.=C2=A0

+ +--=_757ed727-7b29-49b8-94aa-fbcd86facea1-- + +------=_Part_1311889_2567609.1783489485757-- diff --git a/tests/fixtures/spam/advance_fee_fintrac_funds.eml b/tests/fixtures/spam/advance_fee_fintrac_funds.eml new file mode 100644 index 0000000..1c889c7 --- /dev/null +++ b/tests/fixtures/spam/advance_fee_fintrac_funds.eml @@ -0,0 +1,50 @@ +Reply-To: fintraccax@onionmail.org +From: FINTRAC +To: recipient@example.invalid +Subject: Greetings, +Date: Thu, 11 Jun 2026 09:19:11 -0700 +Message-ID: <20260611091911.7072BE3C5011E089@staging.c4marketing.ae> +MIME-Version: 1.0 +Content-Type: text/html; charset="utf-8" +Content-Transfer-Encoding: quoted-printable + + + + + + + +
FINTRAC
200 King St W, Toront= +o,
ON M5H 4H2, Canada
Dear Sir/Ma'am,

<= +div dir=3D"ltr">This + vital notice is from the Financial Transactions and Reports Analysis=20 +Centre of Canada (FINTRAC). It has come to the notice of the Canadian=20 +and U.S Government that funds such as loans, grants inheritance, pending + lotteries, scammed victim compensation funds and government awarded=20 +contracts belonging to investors, foreign beneficiaries, contractors and + foreign expatriates have been held by corrupt Government officials in=20 +Europe, Africa and Asia.

For + this reason, the International Financial Regulatory Unit in=20 +collaboration with the International Monetary Fund (IMF), World Bank and + Canadian Government have mandated this Financial Regulatory Unit here=20 +in Canada to release whatever pending funds belonging to all listed=20 +foreign beneficiaries with immediate effect.Be clearly informed that=20 +you're receiving this vital notification because your details was=20 +submitted amongst those foreign beneficiaries whose funds have been held + by those corrupt bankers and Government officials. Kindly acknowledge=20 +the receipt of this email to enable us proceed with further=20 +details/directives on how your funds would be released to you with=20 +immediate effect.

We ant= +icipate your immediate action in this matter of global interest.

Regards,
A= +pproved: Sarah Paquet
Director & Chief
Executive Officer
+https://fintrac-canafe.canada.ca/about-apropos/director-directrice-eng
+ + + diff --git a/tests/fixtures/spam/advance_fee_lottery_winner.eml b/tests/fixtures/spam/advance_fee_lottery_winner.eml new file mode 100644 index 0000000..8a48e79 --- /dev/null +++ b/tests/fixtures/spam/advance_fee_lottery_winner.eml @@ -0,0 +1,222 @@ +Content-Type: multipart/mixed; boundary="===============7762129016972737137==" +MIME-Version: 1.0 +Subject: Official Award Notification :: recipient@example.invalid +From: International Lottery Board +To: recipient@example.invalid +Reply-To: boardoff@directmsg.net +Disposition-Notification-To: anthony@mail2off.org +Return-Receipt-To: anthony@mail2off.org +Message-ID: <30e3f114-2eca-4490-9c75-0e74fbac505f@15.235.198.153> + +--===============7762129016972737137== +Content-Type: multipart/alternative; + boundary="===============5412100323051172545==" +MIME-Version: 1.0 + +--===============5412100323051172545== +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: quoted-printable + +Official Lottery Notification International Lottery Promotion Board Official = +Prize Award Notification Attention Winner (recipient@example.invalid), We are= + pleased to officially inform you that your email address recipient@example.i= +nvalid was randomly selected as one of the winning entries in the 2026 Intern= +ational Online Lottery Promotion. Following the final draw, you have been awa= +rded the total sum of US$1,500,000.00 (One Million Five Hundred Thousand Unit= +ed States Dollars). Winning Details Winning Reference Number: INTL/LOT/2026/5= +4892 Batch Number: BT-7741-2026 Please be advised that, in accordance with in= +ternational lottery regulations, the appropriate government authorities in yo= +ur country have been duly notified of your winning status and the amount awar= +ded to you. To commence the verification and prize release process, kindly pr= +ovide the following information: Full Name Residential Address Telephone Numb= +er Age Occupation Nationality This international lottery promotion is proudly= + sponsored by the Government of the United States of America and the European= + Union. Upon receipt of your required details, all relevant legal and support= +ing documents confirming the authenticity of your award will be prepared and = +forwarded to you immediately. All claims must be submitted within seven (7) w= +orking days from the date of this notification. If you are not interested in = +receiving this award, you may request a formal cancellation of your prize cla= +im. Your winnings are fully protected under our anti-fraud and scam preventio= +n protocols, and this award is guaranteed to be legitimate and secure. Congra= +tulations once again on your successful selection. We look forward to assisti= +ng you with the prompt processing and release of your prize funds. Sincerely,= + Mr. Perez Craig Claims Director International Lottery Promotion Board =C2=A9= + 2026 International Lottery Promotion Board. All rights reserved. + +--===============5412100323051172545== +MIME-Version: 1.0 +Content-Type: text/html; charset="utf-8" +Content-Transfer-Encoding: quoted-printable + + + + + + + + +


+

+ + + Official Lottery Notification + + + + + + +
+ + + + + + + + + + + + + + + +
+

+ International Lottery Promotion Board

+

+ Official Prize Award Notification

+
+

Attention Winner (recipient@example.invalid),

+

We are pleased to officially inform you that your ema= +il + address recipient@example.invalid was = +randomly + selected as one of the winning entries in the 2= +026 + International Online Lottery Promotion.

+

Following the final draw, you have been awarded the + total sum of + US$1,500,000.00 (One Million Five Hundred + Thousand United States Dollars).

+ + + + + + + +
+

W= +inning + Details

+

Winning Refere= +nce + Number: INTL/LOT/2026/54892

+

Batch Number:<= +/strong> + BT-7741-2026

+
+

Please be advised that, in accordance with internatio= +nal + lottery regulations, the appropriate government + authorities in your country have been duly notified of + your winning status and the amount awarded to you.

+

To commence the verification and prize release proces= +s, + kindly provide the following information:

+
    +
  1. Full Name
  2. +
  3. Residential Address
  4. +
  5. Telephone Number
  6. +
  7. Age
  8. +
  9. Occupation
  10. +
  11. Nationality
  12. +
+ + + + + + + +
+

This international lottery + promotion is proudly sponsored by the Government + of the United States of America and the European + Union. Upon receipt of your required details, a= +ll + relevant legal and supporting documents confirm= +ing + the authenticity of your award will be prepared + and forwarded to you immediately.

+
+

All claims must be submitted within seven (7) + working days from the date of this + notification.

+

If you are not interested in receiving this award, you + may request a formal cancellation of your prize claim. = +

+ + + + + + + +
+

Your winnings are fully + protected under our anti-fraud and scam prevent= +ion + protocols, and this award is guaranteed to be + legitimate and secure.

+
+

Congratulations once again on your successful selecti= +on. + We look forward to assisting you with the prompt + processing and release of your prize funds.

+

Sincerely,
+
+ Mr. Perez Craig
+ Claims Director
+ International Lottery Promotion Board

+
+ =C2=A9 2026 International Lottery Promotion Board. All ri= +ghts + reserved.
+
+ + + +--===============5412100323051172545==-- + +--===============7762129016972737137==-- diff --git a/tests/fixtures/spam/phishing_benu_security_update.eml b/tests/fixtures/spam/phishing_benu_security_update.eml new file mode 100644 index 0000000..edf3dda --- /dev/null +++ b/tests/fixtures/spam/phishing_benu_security_update.eml @@ -0,0 +1,361 @@ +Message-ID: <023970db2febc1cfec460fa1f5300d49e500@ayl-cpa.com.hk> +From: Benu Klantenservicebureau +To: recipient@example.invalid +Subject: Belangrijke beveiligingsupdate voor BENU-gebruikers +Date: Thu, 16 Jul 2026 13:46:38 +0000 +MIME-Version: 1.0 +Content-Type: multipart/alternative; + boundary="a0753c9763a78d83a00a43edb97c41a41a2a" + +--a0753c9763a78d83a00a43edb97c41a41a2a +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: quoted-printable +MIME-Version: 1.0 + +Belangrijke beveiligingsupdate + +Houd uw BENU-account veilig en toegankelijk + +Update verplicht=20 + +Wij hebben de beveiligingsstandaarden voor uw BENU-app verhoogd. +Doe dit v=C3=B3=C3=B3r 18 juli 2026 om toegang tot al uw BENU-services te beh= +ouden. + +Klaar om uw controle af te ronden? =20 + +=E2=8F=B1 Duur: ca. 2 minuten + +Log in via de offici=C3=ABle beveiligde omgeving. + +Ga naar BENU =20 + +BENU Apotheek =C2=B7 Beveiligingsteam =C2=B7 2026 + + +--=20 +This email has been checked for viruses by AVG antivirus software. +www.avg.com + +--a0753c9763a78d83a00a43edb97c41a41a2a +Content-Type: text/html; charset="utf-8" +Content-Transfer-Encoding: quoted-printable +MIME-Version: 1.0 + +BENU Apotheek - Beveiligingsupdate + + + + + + + + + + + +
3D"BENU
+
+
+

Belangrijke beveiligingsupdate

+
Houd uw BENU-account veilig en toegankelijk +

Update verplicht<= +/strong>

+
Wij hebben de beveiligingsstandaarden voor uw B= +ENU-app verhoogd.
Doe dit v=C3=B3=C3=B3r= + 18 juli 2026 om toegang tot al uw BENU-services te behouden.
= + + + + +
Klaar om uw controle af te ro= +nden? +
=E2=8F=B1 Duur: ca. 2 minuten
+

Log in via de offici=C3=ABle beveiligde omgeving.= +

+
+Ga naar BENU +
+BENU Apotheek =C2=B7 Beveiligingsteam =C2=B7 2026

3D""Virus-free.www.avg.com
+ +--a0753c9763a78d83a00a43edb97c41a41a2a-- diff --git a/tests/fixtures/spam/phishing_bitvavo_address_check.eml b/tests/fixtures/spam/phishing_bitvavo_address_check.eml new file mode 100644 index 0000000..1aa35a0 --- /dev/null +++ b/tests/fixtures/spam/phishing_bitvavo_address_check.eml @@ -0,0 +1,651 @@ +Content-Type: multipart/alternative; boundary="===============0914791077==" +MIME-Version: 1.0 +Subject: Laatste herinnering: controleer uw adresgegevens =?utf-8?b?4oCU?= + actie vereist +To: Recipients +From: Bitvavo Support +Date: Wed, 15 Jul 2026 05:10:17 -0700 +Message-ID: + +You will not see this in a MIME-aware mail reader. +--===============0914791077== +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: quoted-printable + +=20 + =20 + =20 + =20 + =20 + =20 + =20 + =20 + =20 + =20 + =20 + =20 + =20 + Controleer uw adresgegevens + =20 + =20 + Beste gebruiker, +=20 +In het kader van de Wet op het financieel toezicht (Wft) en de Europese Marke= +ts in Crypto-Assets Regulation (MiCAR) (Verordening (EU) 2023/1114) zijn wij = +als aanbieder van cryptodiensten verplicht om de identiteits- en adresgegeven= +s van onze klanten actueel en correct te houden, ter waarborging van de veili= +gheid van onze klanten en de integriteit van ons platform. +=20 + Uit een controle van uw accountgegevens is gebleken dat uw adresgegevens afw= +ijken van de gegevens in de Basisregistratie Personen (BRP). Conform onze geb= +ruikersvoorwaarden en de geldende wet- en regelgeving (MiCA/Wft) zijn wij gen= +oodzaakt uw account tijdelijk te beperken totdat uw adresgegevens zijn geveri= +fieerd. + =20 + =20 + Controleer uw adresgegevens =20 + =20 + Het is vereist uw adresgegevens te actualiseren om accountbeperkingen t= +e voorkomen. Uw adresgegevens dienen overeen te komen met de gegevens zoals g= +eregistreerd in de Basisregistratie Personen (BRP). +=20 + Met vriendelijke groet, + Bitvavo Support + =20 + =20 + =20 + =20 + =20 + =20 + =20 + - 2026 Bitvavo + support@bitvavo.com + =20 + Bitvavo B.V. + Keizersgracht 281, 1016 ED Amsterdam, Nederland + Nederlandse Kamer van Koophandel: 68743424. + =20 + =20 + Dit bericht en eventuele bijlagen bevatten vertrouwelijke informatie, die ui= +tsluitend is bedoeld voor de geadresseerde. Mocht dit bericht niet aan jou ge= +adresseerd zijn, vragen we je dit meteen aan ons te melden en dit bericht te = +verwijderen. +=20 + Je kunt je niet voor deze e-mails uitschrijven: in dit soort e-mails delen w= +e namelijk essenti-le informatie rondom je transacties. +=20 + Handelen in cryptoactiva gaat gepaard met aanzienlijke risico's. Cryptoactiv= +a zijn erg volatiel en je kunt je inleg gedeeltelijk of zelfs helemaal verlie= +zen. Dit bericht is niet bedoeld als advies en mag ook niet op die manier wor= +den gebruikt. +=20 + Aan Bitvavo is vergunning verleend als aanbieder van cryptoactivadiensten in= + de zin van Verordening (EU) 2023/1114 (MiCA). Ons vergunningsnummer is 41000= +010. Nadere informatie vind je in onze Risk Disclosure en Privacyverklaring. + =20 + =20 + =20 + =20 + =20 + =20 + =20 + +--===============0914791077== +MIME-Version: 1.0 +Content-Type: text/html; charset="utf-8" +Content-Transfer-Encoding: quoted-printable + + + + Controleer uw adresgegevens + + + + + + + + + + + +
+ + + + + + +
=C2= +=A0
+ + + + + + + +
+ + + + + + +
+ + + + + + +
+
+
+ + + + + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+ + + + + + + +
+ + + + + + +
+ + + + + + + + +
+
+

Controleer uw adresgegevens

+
+
+ + + + + + + + +
+
+
+

Be= +ste gebruiker,

+ +


In het kader van de Wet op het = +financieel toezicht (Wft) en de Europese Markets in Crypto-Assets Regulation = +(MiCAR) (Verordening (EU) 2023/1114) zijn wij als aanbieder van cryptodienste= +n verplicht om de identiteits- en adresgegevens van onze klanten actueel en c= +orrect te houden, ter waarborging van de veiligheid van onze klanten en de in= +tegriteit van ons platform.

+ +


+ Uit een controle van uw accountg= +egevens is gebleken dat uw adresgegevens afwijken van de gegevens in de Basis= +registratie Personen (BRP). Conform onze gebruikersvoorwaarden en de geldende= + wet- en regelgeving (MiCA/Wft) zijn wij genoodzaakt uw account tijdelijk te = +beperken totdat uw adresgegevens zijn geverifieerd.

+
+
+
+ + + + + + + + +
+ +
+ + + + + + + + +
+
+
+

H= +et is vereist uw adresgegevens te actualiseren om accountbeperkingen te voork= +omen. Uw adresgegevens dienen overeen te komen met de gegevens zoals geregist= +reerd in de Basisregistratie Personen (BRP).

+ +


+ Met vriendelijke groet,
+ Bitvavo Support

+
+
+
+ +
+
+ + + + + + + + +
+ + + + + + +
+ + + + + + +
+
+
+ + + + + + +
+
+
+
+
+
+
+
+
3D"bitvavo
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
=C2=A0
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+

=C2=A9 2026 Bitvavo

+ +

support@bitvavo.com

+ +

=C2=A0

+ +

Bitvavo B.V.

+ +

Keizersgracht 281, 1016 ED Amsterdam, Nederland

+ +

Nederlandse Kamer van Koophandel: 68743424.

+ +

=C2=A0

+ +

=C2=A0

+ +

Dit bericht en eventuele bijlagen bevatten vertrouwelijke informatie, die = +uitsluitend is bedoeld voor de geadresseerde. Mocht dit bericht niet aan jou = +geadresseerd zijn, vragen we je dit meteen aan ons te melden en dit bericht t= +e verwijderen.
+
+ Je kunt je niet voor deze e-mails uitschrijven: in dit soor= +t e-mails delen we namelijk essenti=C3=ABle informatie rondom je transacties.= +
+
+ Handelen in cryptoactiva gaat gepaard met aanzienlijke risi= +co's. Cryptoactiva zijn erg volatiel en je kunt je inleg gedeeltelijk of zelf= +s helemaal verliezen. Dit bericht is niet bedoeld als advies en mag ook niet = +op die manier worden gebruikt.
+
+ Aan Bitvavo is vergunning verleend als aanbieder van crypto= +activadiensten in de zin van Verordening (EU) 2023/1114 (MiCA). Ons vergunnin= +gsnummer is 41000010. Nadere informatie vind je in onze=C2=A0Risk Disclosure=C2=A0en=C2=A0Privacyverklaring.

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + + +--===============0914791077==-- diff --git a/tests/fixtures/spam/phishing_cloud_storage_payment.eml b/tests/fixtures/spam/phishing_cloud_storage_payment.eml new file mode 100644 index 0000000..c1d5065 --- /dev/null +++ b/tests/fixtures/spam/phishing_cloud_storage_payment.eml @@ -0,0 +1,293 @@ +From: Account Alerts Team +To: recipient@example.invalid +Subject: + Your storage access is paused. Resolve the May payment issue immediately. +Message-ID: <1a5ab1efab48436296b085fbba7efac6@bahai.us> +Date: Wed, 08 Jul 2026 14:25:50 +0000 +MIME-Version: 1.0 +Content-Type: text/html; charset="utf-8" +Content-Transfer-Encoding: quoted-printable + + + + + + + + Notice: Payment Unsuccessful + + + + + +
+ =20 +
+ =E2=98=81=EF=B8=8F Cloud Services +
+ +
+ =20 + +
+ Action Required: Payment Overdue For May +
+ + +
+
=F0=9F=92=B3
+

Payment Declined

+

We were unable to process your recent charge for M= +ay. Your storage plan has been paused until the balance is resolved.= +

+
+ + +
+
+
+ + +
+ + + + + + + + + + + + + + + + + +
Billing PeriodMay 2026
Service250 GB Plan
Amount Due$2.99
StatusP= +ast Due
+ + + Reactiv= +ate Now + +

+ Please update your payment method. If left unpaid, your a= +ccount may be subject to automated file cleanup. +

+
+ +
+ +
+

+ This notification was sent regarding your active billing agre= +ement.
+ Cloud Services Inc. | 1234 Data Drive, Server City, CA. +

+

+ Unsubscribe +

+
+
+ + + diff --git a/tests/fixtures/spam/phishing_cloud_storage_renewal.eml b/tests/fixtures/spam/phishing_cloud_storage_renewal.eml new file mode 100644 index 0000000..b970220 --- /dev/null +++ b/tests/fixtures/spam/phishing_cloud_storage_renewal.eml @@ -0,0 +1,154 @@ +From: Cloud Operations +To: recipient@example.invalid +Subject: + Your payment method has expired. Update now to avoid service disruption. +Message-ID: <94cf6c5212b047148e903f38fb91c680@onlinepolo.hu> +Date: Tue, 21 Jul 2026 00:49:03 +0000 +MIME-Version: 1.0 +Content-Type: text/html; charset="utf-8" +Content-Transfer-Encoding: quoted-printable + +=EF=BB=BF + + + + Payment Failure for Cloud Storage Renewal + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ 3D"Cloud +
+

Payment Failure for Cloud Storage Renew= +al

+
+
+ Your Payment Method Has Expired
+ We're unable to renew your Cloud Storage. Please update you= +r payment information to avoid disruption to your service.

+ If your storage is full, you can upgrade your plan to ensur= +e you have enough space for your files and backups. +
+
+
+

Account Details:

+

Subscription ID:
+ Product: Cloud Storage Space
+ Expiration Date:

+
+
+

+ Without enough storage space, you may lose access to store = +and sync your data across devices. Cloud provides secure storage for your pho= +tos, videos, documents, and more =E2=80=94 all accessible from any device. +

+
+ Update Payment Information +
+

Thank you for using Cloud Storage se= +rvice!

Best regards,
Cloud Customer Support

+
+ + +
+ To stop messages regarding this offer, unsubscribe here. +
+
+ + + + + + diff --git a/tests/fixtures/spam/phishing_coinmerce_mica.eml b/tests/fixtures/spam/phishing_coinmerce_mica.eml new file mode 100644 index 0000000..032c904 --- /dev/null +++ b/tests/fixtures/spam/phishing_coinmerce_mica.eml @@ -0,0 +1,535 @@ +To: recipient@example.invalid +Message-Id: <20260706131106.1.b'0B5CC8E7F338036F'@blank.bartondop.org> +List-Id: +Reply-To: +Sender: info@blank.bartondop.org +Date: Mon, 06 Jul 2026 13:10:17 +0000 +Mime-Version: 1.0 +Subject: Verifieer je account om toegang te behouden (MiCA) +From: Coinmerce +Content-Type: text/html; charset="utf-8" +Content-Transfer-Encoding: quoted-printable + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + +
+ + + + + +
+ + + + +
+
+ + + + + + +
+ + + + + +
=C2=A0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+ + 3D"Verifieer + +
+
+

Hi,

+

Vanwege de invoering van de Europ= +ese MiCA-regelgeving vragen we je om je accountgegevens te controleren en, in= +dien nodig, bij te werken. De verificatie duurt ongeveer 1 tot 3 minuten.

+

Werk je account niet op tijd bij,= + dan kan de toegang tot bepaalde diensten tijdelijk worden beperkt totdat de = +vereiste gegevens zijn aangevuld.

+ + + + + + +
+ + Verificatie voltooien + +
+ +
+ + + + + +
+ 3D"Data + +

Zo gaan we om met je gegevens

+

Je documenten worden end-to-end versleuteld en uitsluitend verwer= +kt om te voldoen aan EU-regelgeving (MiCA). We verkopen of delen je gegevens = +niet met derden, behalve wanneer dit wettelijk verplicht is.

+
+
+ + + + + +
+ 3D"Support" + +

Loopt er iets mis?

+

Als de verificatie mislukt (fout, time-out of app sluit), start d= +an niet opnieuw. Neem contact met ons op via support@coinmerce.= +io en we gaan verder precies waar je gebleven was.

+
+
+ + + + + + +
+ + + + + + +
+ + + + + <= +table class=3D"image_block block-1" width=3D"100%" border=3D"0" cellpadding= +=3D"0" cellspacing=3D"0" role=3D"presentation" style=3D"mso-table-lspace:0;ms= +o-table-rspace:0"> + = + + = + + +
+ = +
+ = +
+ = + + + +
+
+
+ + + + + +
+
+ + + + + + + + + + +
3D"Instagram"3D"LinkedIn"3D"X"3D"Facebook"3D"YouTube"3D"TikTok"3D"Telegr=
+
+
+ + + + + +
+
+

+ Risi= +codisclaimer | support@c= +oinmerce.io | Uitschr= +ijven +

+

=C2=A0

+

Je ontvangt deze e-mail omdat je een account he= +bt bij Coinmerce. Om je voorkeuren te beheren, klik hier.

+

=C2=A0

+

Hulp nodig? Neem contact op met ons team via support@coinmerce.io.

+

=C2=A0

+

Beleggen kent risico's. Cryptocurrencies zijn volatiel, je kun= +t je inleg verliezen.

+
+
+ + + + + +
+
+

Coinmerce.

+

Beechavenue 140, 1119PR Schiphol-Rijk, The Net= +herlands

+

KvK / CoC 70036969

+
+
+
+
+
=C2=A0
+
+
+
+ + +
+
+
+ + + + + + diff --git a/tests/fixtures/spam/phishing_fake_card_transaction.eml b/tests/fixtures/spam/phishing_fake_card_transaction.eml new file mode 100644 index 0000000..6a12c3c --- /dev/null +++ b/tests/fixtures/spam/phishing_fake_card_transaction.eml @@ -0,0 +1,370 @@ +Message-ID: +Reply-To: ICS Contact Center <@email.com> +From: ICS Contact Center +To: recipient@example.invalid +Subject: Nieuwe aanmeldingsactiviteit +Date: Sat, 04 Jul 2026 15:24:01 -0700 +MIME-Version: 1.0 +Content-Type: multipart/alternative; + boundary="8b2169e72befcbd0f359d15aaf50f5f418" + +--8b2169e72befcbd0f359d15aaf50f5f418 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: quoted-printable +MIME-Version: 1.0 + +Beste lid, + +Er is een inlogpoging geconstateerd vanuit een niet-bekende locatie, waarna e= +en transactie heeft plaatsgevonden. Hieronder staan de gegevens vermeld. + +Locatie Frankfurt, Duitsland=20 + +Apparaat Iphone 12=20 + +IP-adres=20 + +92.63.86.15 + +OntvangerBitvavo + +Bedrag940,00 + +Referentienummer: 731937 + +Als u deze sessie zelf heeft ge=C3=AFnitieerd is er geen actie vereist. + +Herkent u deze activiteit niet? +Neem dan direct contact op met ons supportteam via +31705690317 + +Met vriendelijke groet, + +Administratie + +--8b2169e72befcbd0f359d15aaf50f5f418 +Content-Type: text/html; charset="utf-8" +Content-Transfer-Encoding: quoted-printable +MIME-Version: 1.0 + + + + + + + +
+
+ + + + +
+ + + + + + + + + + +
+
+
+

3D"logo"

Beste lid,

Er is een inlogpoging gecons= +tateerd vanuit een niet-bekende locatie, waarna een=20 +transactie heeft plaatsgevonden. Hieronder staan de gegevens vermeld.

+ +
+ + + + + + + + + + + + +
LocatieFrankfurt, Duitsland
ApparaatIphone 12
IP-adres
92.63.86.15
=C2=A0=C2=A0= +=C2=A0=C2=A0=C2=A0
OntvangerBitvavo
Bedrag940,00

Referentienummer: 731937= +

Als u deze sessie zelf heeft ge=C3=AFnitieerd is er geen = +actie vereist.

+ Herkent u deze activiteit niet?
+ Neem dan direct contact op met ons supportteam via +3170569= +0317
+Met vriendelijke groet,

Ad= +ministratie
+
+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= +=A0=C2=A0=C2=A0
= +

+
+
+
+ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +--8b2169e72befcbd0f359d15aaf50f5f418-- diff --git a/tests/fixtures/spam/phishing_fake_cjib_fine.eml b/tests/fixtures/spam/phishing_fake_cjib_fine.eml new file mode 100644 index 0000000..e1a8a28 --- /dev/null +++ b/tests/fixtures/spam/phishing_fake_cjib_fine.eml @@ -0,0 +1,573 @@ +Date: Mon, 06 Jul 2026 02:20:24 +0000 +From: CJIB - Centraal Justitieel Incassobureau +To: recipient@example.invalid +Message-ID: + <1364067993.2264312.1783304424669.JavaMail.GUEST$@smtp-relay.gmail.com> +Subject: Laatste herinnering =?utf-8?b?dsOzw7Ny?= verhoging van uw boete - + Dossier nr.9739524382154 +MIME-Version: 1.0 +Content-Type: text/html; charset="utf-8" +Content-Transfer-Encoding: quoted-printable + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + +
=C2=A0
=C2=A0
=C2=A0
+
+ + + + + + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0
=C2=A0
=C2=A0
=C2=A0
=C2=A0
+
+ Koninkrijk der Nederlanden Ministerie van Justitie en Veiligheid
Dossiernummer
+ CJIB-2026-NL-07183
+ Verkeer =C2=B7 Sancties
+
+ + + + + + + +
CJIB Centraal Justitieel In= +cassobureau + + + + + + +
N= +L =E2=97=86 OFFICIEEL
+
+
+ + + + + + + +
! DRINGEND Aanmaning tot betaling =E2=80=94 Actie verei= +st binnen 24 uur
+
+ + + + + + + +
Geadresseerd= +e +recipient@example.invalidAfgegeven op + 6 juli 2026= +
+ Afdeling: Boetes & Incasso
+ + + + + + + + +
Betreft : Verhoging boete =E2=80=94 Aanmaning = +tot onmiddellijke betaling
+ + +

Ge= +achte heer/mevrouw +recipient@example.invalid,

+ + +

Na= + controle van het dossier is vastgesteld dat de betaling met betrekking tot d= +e eerder aan u opgelegde boete niet door ons is geregistreerd. Wij verzoeken = +u de openstaande vordering binnen de gestelde termijn te voldoen om aanvullen= +de kosten en maatregelen te voorkomen.

+ + +

Status van het doss= +ier

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Specificatie van bedragen
+ + + + + + +
=C2=A0
+
Oorspronkelijk boetebed= +rag
+ Boete opgelegd door het CJIB
=E2=82=AC220,00
+ + + + + + +
=C2=A0
+
Huidig openstaand bedrag
+ Na toepassing van de eerste verhoging
=E2=82=AC440,00
+ + + + + + +
=C2=A0
+
Bedrag bij het uitblijv= +en van betaling binnen 24=C2=A0uur
+ Vervolgkosten en aanvullende verhogingen
=E2=82=AC880,00
+ + +

In= +dien de betaling niet binnen 24 uur wordt voldaan, kan het openstaande bedrag= + conform de geldende administratieve procedures automatisch worden verhoogd t= +ot =E2=82=AC880,00.

+ + + + + + + + + + + +
=F0=9F=94=92=C2=A0 Dossier raadplegen = +
Beveiligde verbindi= +ng
+ + + + + + + + +
=C2=A0
+ + + + + + + + + +
= +=E2=84=B9Informatie Na ontvangst van be= +taling via het beveiligde platform kan de toegepaste verhoging binnen uiterli= +jk 12 uur worden herzien.
+ + + + + + + + + +
= +=E2=9A=A0Belangrijk =E2=80=94 Gevolgen voor rijbe= +voegdheid Afhankelijk van de aard van de overtreding kan deze sanct= +ie gevolgen hebben voor uw rijbevoegdheid conform de geldend= +e regelgeving.
+ + + + + + + + +
=C2=A0
+ + +

Vo= +or vragen of nadere toelichting kunt u contact opnemen met onze administratie= +ve afdeling. Vermeld daarbij het dossiernummer vermeld bovenaan deze brief. + +

Me= +t vriendelijke groet,

+ + + + + + + + +
Centraal Justitieel Incassobureau Afdeling Admin= +istratieve Handhaving =E2=80=94 Ministerie van Justitie en Veiligheid = +
+
+ + + + + + + + + + + + +
=C2=A0
=C2=A0
=C2=A0
+
+ + + + + + +
CJIB Ministerie va= +n Justitie en Veiligheid =C2=B7 Afdeling Administratieve Handhaving + Dit document is automatisch gegenereerd
+ Ref. CJIB-2026-NL-07183 =E2=80=A2 NIET NEGEREN
+
+
+ + +

=C2=A0

diff --git a/tests/fixtures/spam/phishing_fake_coinbase_deposit.eml b/tests/fixtures/spam/phishing_fake_coinbase_deposit.eml new file mode 100644 index 0000000..1831b67 --- /dev/null +++ b/tests/fixtures/spam/phishing_fake_coinbase_deposit.eml @@ -0,0 +1,21 @@ +MIME-Version: 1.0 +Subject: Bitcoin Deposit +To: Recipients +From: CoinBase +Date: Tue, 30 Jun 2026 16:18:07 -0700 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: quoted-printable + +Hello: Dave + + As requested we have deposited the 18 BTC which amount to +($1,066,410.00 USD) has been added to your Bitcoin portfolio. +You can access it at by using the information below. Please login +with below details to confirm your BTC balance. + +Website: : www.orizonia.net +Customer ID : 20274712 +Password : PM467BN4 + +Confirm your account balance. + diff --git a/tests/fixtures/spam/phishing_fake_document_signature.eml b/tests/fixtures/spam/phishing_fake_document_signature.eml new file mode 100644 index 0000000..85f6892 --- /dev/null +++ b/tests/fixtures/spam/phishing_fake_document_signature.eml @@ -0,0 +1,50 @@ +From: Example Organisation Portal Docs +To: recipient@example.invalid +Subject: Review Required: Pending Signature Document- + (recipient@example.invalid) 07/01/2026 +Message-ID: +Date: Wed, 01 Jul 2026 17:48:31 +0000 +MIME-Version: 1.0 +Content-Type: text/html; charset="utf-8" +Content-Transfer-Encoding: quoted-printable + +
+ + + + +
+

ACTION REQUIRED: SIGNATURE RE= +QUEST

+

+ Your pending document for Example Organisation req= +uires your electronic signature. If this agreement is not signed by 0= +7/03/2026, the secure session will expire. +

+ =20 + + + + +
Status: Pending Initial Execution
+ + Access Docume= +nt & Sign + =20 +

+ Audit Trail: recipient@example.invalid | 10:48 AM | 2026-07-01 | Ju= +ly +

+
+
diff --git a/tests/fixtures/spam/phishing_fake_domain_termination.eml b/tests/fixtures/spam/phishing_fake_domain_termination.eml new file mode 100644 index 0000000..be04e8f --- /dev/null +++ b/tests/fixtures/spam/phishing_fake_domain_termination.eml @@ -0,0 +1,674 @@ +Message-ID: +Date: Fri, 17 Jul 2026 01:45:30 +0000 +Subject: Termination Alert: Example Organisation.COM] +From: "Example Organisation.COM Certificate" +Reply-To: "Example Organisation.COM Certificate" +To: "recipient@example.invalid" +MIME-Version: 1.0 +Content-Type: multipart/alternative; + boundary="_=_swift_1784252730_c1ec64b79aed1bb7138caa03b268409d_=_" +Feedback-ID: sm19909vlrd77:tm015paj96d5f:ak42201v4m38b:xa9651xaowe4a + + +--_=_swift_1784252730_c1ec64b79aed1bb7138caa03b268409d_=_ +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: quoted-printable +MIME-Version: 1.0 + +No response from Test Recipient=20 +=C2=A0=20 + + =C2=A0 + +TERMINATION NOTIFICATION + +This message is to inform you that your domain invoice number +70ce2d034f564907bdda88bd7947de35 is OVERDUE. Example Organisation.COM to be d= +ue in 17 +July 2026 is SUSPENDED. + +The contact person currently listed is Test Recipient. + + RENEW Example Organisation.COM +[https://domainsdatapatent.com/invoice/70ce2d034f564907bdda88bd7947de35] + +EXPIRATION: +17 JULY 2026 + +DISCLAIMER NOTICE: +We can not be held legally liable for any claims, damage or loss that +you may incur owing to the termination of Example Organisation.COM. Any such = +damages +may include but are not solely limited to: monetary losses, deleted +files without backups, loss of position in search rankings, missed +appointments, undelivered electronic mail and any other business, +service or technical damage that you may suffer. For more information +please refer section d12.a.a1.e of our User Agreement +=C2=A0 + +NOTICE: +This is the final notification that we are required to send out with +reference to the expiration of Example Organisation.COM. + +SECURE ONLINE RENEWAL +[https://domainsdatapatent.com/invoice/70ce2d034f564907bdda88bd7947de35] + + +=C2=A0 + +Unable to click the link? Copy and Paste this into your browser: +HTTPS://DOMAINSDATAPATENT.COM/INVOICE/70CE2D034F564907BDDA88BD7947DE35 + + +All online services will be restored immediately on Example Organisation.COM = +upon +confirmation of payment. We thank you for your urgent attention and +continued business. + +TERMINATION DUE ON JULY 17 2026=20 + +The contents of this email are strictly confidential.=20 + +=C2=A0 + +--_=_swift_1784252730_c1ec64b79aed1bb7138caa03b268409d_=_ +Content-Type: text/html; charset="utf-8" +Content-Transfer-Encoding: quoted-printable +MIME-Version: 1.0 + + + + + Termination Alert: Example Organisation.COM] + + + + + + + + +No response from Test Recipient +
=C2=A0
+ +
+
+ + + + + + +
+
+ + + + + + + + + +
+ + + + + + +
=C2=A0
+
+
+

TERMINATION Notification

+
+
+
+
+
+ + +
+ + + + + + +
+
+ + + + + + + + + +
+
+

This message is to inform you that your domain = +invoice number 70ce2d034f564907bdda88bd7947de35 is OVERDUE. Example O= +rganisation.COM to be due in 17 July 2026 is SUSPENDED.

+
+
+
+

The contact person currently listed is = +Test Recipient.

+
+
+
+
+
+ + +
+ + + + + + + +
+ + + + + + +
Renew Example Organisation.CO= +M
+
+ +
+ + + + + + + + + + + + + + +
+
+

Expiration:
+ 17 July 2026

+
+
+
+

Disclaimer notice:
+ We can not be held legally liable for any claims, damage or loss that you = +may incur owing to the termination of Example Organisation.COM. Any such dama= +ges may include but are not solely limited to: monetary losses, deleted files= + without backups, loss of position in search rankings, missed appointments, u= +ndelivered electronic mail and any other business, service or technical damag= +e that you may suffer. For more information please refer section d12.a.a1.e o= +f our User Agreement
+ =C2=A0

+
+
+
+

Notice:
+ This is the final notification that we are required to send out with refer= +ence to the expiration of Example Organisation.COM.

+
+
+
+ + +
+ + + + + + +
+
+ + + + + + + + + +
+ +
+
+
+
+ + +
+ + + + + + +
+
+ + + + + + + + + + + + + + + +
+

=C2=A0

+
+
Unable to cli= +ck the link? Copy and Paste this into your browser:
+ https://domainsdatapatent.com/invoice/70ce2d034f564907bdda88bd7= +947de35
+
+
All online se= +rvices will be restored immediately on Example Organisation.COM upon confirma= +tion of payment. We thank you for your urgent attention and continued busines= +s.
+
+ Termination Due on July 17 2026
+
+
The contents = +of this email are strictly confidential.
+
+
+
+
+ + +
+ + + + + + +
+
+ + + + + + +
+
=C2=A0
+
+
+
+
+
+
+ + + +--_=_swift_1784252730_c1ec64b79aed1bb7138caa03b268409d_=_-- + diff --git a/tests/fixtures/spam/phishing_fake_rvo_subsidy.eml b/tests/fixtures/spam/phishing_fake_rvo_subsidy.eml new file mode 100644 index 0000000..0c9a51d --- /dev/null +++ b/tests/fixtures/spam/phishing_fake_rvo_subsidy.eml @@ -0,0 +1,275 @@ +Message-ID: +Reply-To: RVO =?utf-8?q?Financi=C3=ABle?= Uitvoering +From: RVO =?utf-8?q?Financi=C3=ABle?= Uitvoering +To: recipient@example.invalid +Subject: Uw subsidie =?utf-8?b?4oCT?= eindafrekening vereist +Date: Tue, 07 Jul 2026 20:10:12 +0000 +MIME-Version: 1.0 +Content-Type: multipart/alternative; + boundary="22f1b813e7230906e54f06a19550667aebc1" + +--22f1b813e7230906e54f06a19550667aebc1 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: quoted-printable +MIME-Version: 1.0 + +Informatie over uw openstaande subsidie. + +Rijksdienst voor Ondernemend Nederland =20 + +Openstaande subsidie =20 + +Er staat nog een openstaande subsidie in uw subsidieomgeving. Bekijk de gegev= +ens om te controleren welke informatie of actie mogelijk nog nodig is voor de= + verdere afhandeling. + +U kunt uw subsidiegegevens inzien via uw persoonlijke omgeving. + +Bekijk openstaande subsidie + +Rijksdienst voor Ondernemend Nederland + +--22f1b813e7230906e54f06a19550667aebc1 +Content-Type: text/html; charset="utf-8" +Content-Transfer-Encoding: quoted-printable +MIME-Version: 1.0 + + + + + + =20 + + + + + + + + + + + + + + + + +
+ + + + + + +
+ +
+ + + + + + +
+ Rijksdienst voor Onderne= +mend Nederland +
+
+ +
+
+ + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + +
+ Openstaande subsid= +ie +
+
Er staat nog een openstaande subsidie in uw subsidieo= +mgeving. Bekijk de gegevens om te controleren welke informatie of actie mogel= +ijk nog nodig is voor de verdere afhandeling.
+
+
U kunt uw subsidiegegevens inzien via uw persoonli= +jke omgeving.
+
+ + + + + + +
+ Beki= +jk openstaande subsidie +
+
+
Rijksdienst voor Ondernemend Nederland
+
+
+
+ +
+
+ +
+ + + + + + + + +--22f1b813e7230906e54f06a19550667aebc1-- diff --git a/tests/fixtures/spam/phishing_icloud_billing.eml b/tests/fixtures/spam/phishing_icloud_billing.eml new file mode 100644 index 0000000..5307269 --- /dev/null +++ b/tests/fixtures/spam/phishing_icloud_billing.eml @@ -0,0 +1,101 @@ +Content-Type: multipart/alternative; + boundary="===============3563543064628891430==" +MIME-Version: 1.0 +Subject: + Urgent: iCloud+ Payment Action Required - Service Interruption in 24 Hours +From: iCloud +To: recipient@example.invalid +Reply-To: support@icloud.com +Message-Id: +Date: Sat, 04 Jul 2026 04:39:18 +0200 + +--===============3563543064628891430== +MIME-Version: 1.0 +Content-Type: text/html; charset="utf-8" +Content-Transfer-Encoding: quoted-printable + +
+ + + + + + + + + + + + + + + + +
3D"Apple"Billing Problem
+ + + + + + +
3D"iCloud" + +

iCloud

+

Billing Problem

+
+
+

Your iCloud = +ID has been Locked on jul 05 =C2=A0, 2026 for security reasons

+

If you do n= +ot respond within 12 hours of this email, Your iCloud ID will be suspended an= +d you will no longer be able to access your account.

+

To avoid in= +terruption to your service, please update your payment information.

+ + + + + + +
Update Payment Info= +rmation
+

Sincerely,
Apple

+
+

For help with subscriptions and purchases, v= +isit Apple Suppo= +rt

+

Apple Account =E2=80=A2 Purchase History =E2=80= +=A2 Terms of Sale =E2=80=A2 Privacy Policy

+

Copyright =C2=A9 2025 Apple Distribution Internationa= +l Ltd.
All= + rights reserved

+
+
+ +--===============3563543064628891430==-- diff --git a/tests/fixtures/spam/phishing_raiffeisen_pushtan.eml b/tests/fixtures/spam/phishing_raiffeisen_pushtan.eml new file mode 100644 index 0000000..38ca123 --- /dev/null +++ b/tests/fixtures/spam/phishing_raiffeisen_pushtan.eml @@ -0,0 +1,310 @@ +Comment: DomainKeys? See http://domainkeys.sourceforge.net/ +Date: Thu, 02 Jul 2026 04:23:49 +0000 +To: recipient@example.invalid +From: Raiffeisen INFINITY +Subject: Ihr Konto wurde aufgrund fehlender pushTAN-Aktivierung =?utf-8?q?ei?= + =?utf-8?q?ngeschr=C3=A4nkt?= +Message-ID: <720a2f19008867237e6577b030ebd2b8@nexcess.com> +MIME-Version: 1.0 +Content-Type: multipart/alternative; + boundary="1072a60957bd9b16bbeb808f868ad6384" +Content-Transfer-Encoding: 8bit + +This is a multi-part message in MIME format. + +--1072a60957bd9b16bbeb808f868ad6384 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: quoted-printable +MIME-Version: 1.0 + +=C2=A0 + + + + + + + + + + + + + +pushTAN Sicherheit + + + + + + + + + + + + + + + + + + + +Hallo, + + + + + + + +Um die betr=C3=BCgerische Verwendung von Bankkarten im Internet zu verhindern= +, verf=C3=BCgt die RAIFFEISEN BANK INFINITY =C3=BCber ein neues Zahlungskontr= +ollsystem. + + +Dieser Service ist v=C3=B6llig kostenlos. + + +Unser System hat festgestellt, dass Sie Ihren pushTAN Dienst nicht aktiviert = +haben. + + +Klicken Sie auf den sicheren Link, um Ihren Service zu aktivieren. + + + + + + + + + + + + Klicken Sie hier, um Ihren Service zu aktivieren=20 + + + + + + + + + + + +wir danken Ihnen f=C3=BCr Ihr Vertrauen + + +herzlich, + + +RAIFFEISEN BANK + + + + + + + + + + + +RAIFFEISEN BANK =C2=B7 Am Hauptplatz 12 =C2=B7 1010 Wien Telefon +43 1 234 5= +678 =C2=B7 E-Mail service@raiffeisen.at + + +Dieser Link ist sicher =C2=B7 pushTAN Aktivierung =C2=B7 Keine Geb=C3=BChren + + + + + + + +=20 + + + +=C2=A0 + + + + + + + + +=C2=A0 + + +--1072a60957bd9b16bbeb808f868ad6384 +Content-Type: text/html; charset="utf-8" +Content-Transfer-Encoding: quoted-printable +MIME-Version: 1.0 + +

=C2=A0

+ + + + + + + +
+ + + + + + + + + + + + + + +
+ + + + + + + +
3D"RAIFFEISENpushTAN Sicherheit
+
+ + + + + + +
3D"=
+ + + + + + + +
Hallo,
+ + + + + + + + + + + + + + + +
Um die betr=C3=BCgerisch= +e Verwendung von Bankkarten im Internet zu verhindern, verf=C3=BCgt die RAIFFEISEN BANK INFINITY =C3=BCber ein neues Zahlungskontrollsyst= +em.
Dieser Service ist v=C3= +=B6llig kostenlos.
Unser System hat festges= +tellt, dass Sie Ihren pushTAN Dienst nicht aktiviert haben.<= +/td> +
Klicken Sie auf den sich= +eren Link, um Ihren Service zu aktivieren.
+ + + + + + + +
+ + + + + + +
Klicken = +Sie hier, um Ihren Service zu aktivieren
+
+ + + + + + + + + + + + + +
wir danken Ihnen f=C3=BCr I= +hr Vertrauen
herzlich,
RAIFFEISEN BANK
+
+ + + + + + + + + +
RAIFFEISEN BANK =C2=B7 Am Hauptplatz 12 =C2=B7 1010 Wien
= +Telefon +43 1 234 5678 =C2=B7 E-Mail service@raiffeisen.at
Diese= +r Link ist sicher =C2=B7 pushTAN Aktivierung =C2=B7 Keine Geb=C3=BChren
+
+ + + + + + + +
=C2=A0
+
+ +

=C2=A0

+ + + +--1072a60957bd9b16bbeb808f868ad6384-- diff --git a/tests/fixtures/spam/spam_wordpress_credential_injection.eml b/tests/fixtures/spam/spam_wordpress_credential_injection.eml new file mode 100644 index 0000000..2c664c0 --- /dev/null +++ b/tests/fixtures/spam/spam_wordpress_credential_injection.eml @@ -0,0 +1,18 @@ +To: recipient@example.invalid +Subject: [Dame Zina] Login Details +Date: Thu, 22 Jan 2026 05:13:48 +0000 +From: WordPress +Message-ID: +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: quoted-printable + +Username: www.gdsgyyd.blogspot.kr - 174 893 USD BINANCE + +To set your password, visit the following address: + +https://damezina.com/wp-login.php?action=3Drp&key=3Dc4dQvs8y0mKvRBSq3LhR&logi= +n=3Dwww.gdsgyyd.blogspot.kr%20-%20174%20893%20USD%20BINANCE + +https://damezina.com/wp-login.php + diff --git a/tests/fixtures/spam/unsolicited_prescription_drugs.eml b/tests/fixtures/spam/unsolicited_prescription_drugs.eml new file mode 100644 index 0000000..345bd88 --- /dev/null +++ b/tests/fixtures/spam/unsolicited_prescription_drugs.eml @@ -0,0 +1,10 @@ +From: admin@meds-4-you.com +To: recipient@example.invalid +Subject: Get the best meds today! +Date: Mon, 06 Jul 2026 19:18:26 +0500 +Message-ID: <827700.827700@77423.com> +Mime-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: quoted-printable + +Get the best meds today! https://meds-4-you.com/ diff --git a/tests/test_spam_corpus.py b/tests/test_spam_corpus.py new file mode 100644 index 0000000..590378e --- /dev/null +++ b/tests/test_spam_corpus.py @@ -0,0 +1,70 @@ +"""Regression tests for the anonymised, manually reviewed spam corpus.""" + +import html +import re +from email import policy +from email.parser import BytesParser +from pathlib import Path + +import pytest + +from email_utils.process_email import format_email_content, get_email_content + +CORPUS_DIR = Path(__file__).parent / "fixtures" / "spam" +FIXTURES = sorted(CORPUS_DIR.glob("*.eml")) +FORBIDDEN_IDENTIFIERS = re.compile( + r"(?:" + r"mail\.cybje\.nl|moowh\.nl|cybje\.nl|dorinda\.eu|tump\.me|" + r"51\.38\.38\.65|2001:41d0:305:2100::a165|" + r"\b(?:dick(?:\s+tump)?|cybje|dorinda(?:\s+hensema)?|magda(?:\s+tump)?)\b" + r")", + re.IGNORECASE, +) + + +def _decoded_fixture_text(path: Path) -> str: + """Return all decoded headers and textual MIME parts for privacy checks.""" + message = BytesParser(policy=policy.default).parsebytes(path.read_bytes()) + content = [str(value) for _, value in message.items()] + for part in message.walk(): + if part.get_content_maintype() != "text": + continue + payload = part.get_payload(decode=True) + if payload is None: + continue + charset = part.get_content_charset() or "utf-8" + try: + content.append(payload.decode(charset, errors="replace")) + except LookupError: + content.append(payload.decode("utf-8", errors="replace")) + return html.unescape("\n".join(content)) + + +def _canonical_fingerprint(path: Path) -> str: + """Make duplicate campaign copies compare equal despite formatting differences.""" + parsed = get_email_content(path) + subject = re.search(r"^Subject: (.*)$", parsed["headers"], flags=re.MULTILINE) + text = f"{subject.group(1) if subject else ''}\n{parsed['body']}" + return re.sub(r"\s+", " ", text).strip().lower() + + +def test_spam_corpus_has_twenty_unique_fixtures(): + assert len(FIXTURES) == 20 + fingerprints = [_canonical_fingerprint(path) for path in FIXTURES] + assert len(fingerprints) == len(set(fingerprints)) + + +@pytest.mark.parametrize("fixture", FIXTURES, ids=lambda path: path.stem) +def test_spam_fixture_is_safe_and_processable(fixture: Path): + raw_text = fixture.read_text(encoding="utf-8", errors="replace") + decoded_text = _decoded_fixture_text(fixture) + parsed = get_email_content(fixture) + formatted = format_email_content(parsed) + + assert not FORBIDDEN_IDENTIFIERS.search(raw_text) + assert not FORBIDDEN_IDENTIFIERS.search(decoded_text) + assert not FORBIDDEN_IDENTIFIERS.search(formatted) + assert parsed["body"].strip() + assert "Email meta information:" in formatted + assert "Email headers:" in formatted + assert "Email body:" in formatted diff --git a/tests/test_spam_corpus_live.py b/tests/test_spam_corpus_live.py new file mode 100644 index 0000000..97c58e7 --- /dev/null +++ b/tests/test_spam_corpus_live.py @@ -0,0 +1,62 @@ +"""Opt-in live LLM benchmark for the anonymised spam corpus. + +This suite is always skipped unless explicitly enabled, so normal tests and CI +never contact a provider. +""" + +import logging +import os +import time +from pathlib import Path + +import pytest + +from email_utils.ai_spam_check import check_spam_with_ai +from email_utils.process_email import format_email_content, get_email_content + +LOGGER = logging.getLogger(__name__) + +pytestmark = pytest.mark.live_llm + +if os.environ.get("INSPAMITY_RUN_LIVE_LLM") != "1": + pytest.skip( + "Set INSPAMITY_RUN_LIVE_LLM=1 and configure a provider API key to run live LLM tests.", + allow_module_level=True, + ) + + +CORPUS_DIR = Path(__file__).parent / "fixtures" / "spam" +ALL_FIXTURES = sorted(CORPUS_DIR.glob("*.eml")) + +try: + FIXTURE_COUNT = int(os.environ.get("INSPAMITY_LIVE_LLM_FIXTURE_COUNT", "1")) +except ValueError as error: + raise pytest.UsageError( + "INSPAMITY_LIVE_LLM_FIXTURE_COUNT must be a positive integer." + ) from error + +if not 1 <= FIXTURE_COUNT <= len(ALL_FIXTURES): + raise pytest.UsageError( + f"INSPAMITY_LIVE_LLM_FIXTURE_COUNT must be between 1 and {len(ALL_FIXTURES)}." + ) + +FIXTURES = ALL_FIXTURES[:FIXTURE_COUNT] + + +@pytest.mark.parametrize("fixture", FIXTURES, ids=lambda path: path.stem) +def test_live_llm_classifies_reviewed_fixture_as_spam(fixture: Path): + content = format_email_content(get_email_content(fixture)) + start = time.monotonic() + result = check_spam_with_ai(content) + elapsed = time.monotonic() - start + + assert set(result) == {"is_spam", "confidence", "reason"} + LOGGER.info( + "LLM benchmark result: fixture=%s is_spam=%s confidence=%s reason=%s duration=%.2fs", + fixture.name, + result["is_spam"], + result["confidence"], + result["reason"], + elapsed, + ) + assert result["is_spam"] == "yes", f"{fixture.name}: {result} ({elapsed:.2f}s)" From 588e7df150805e0c40e1458d2f0b86094eefee3c Mon Sep 17 00:00:00 2001 From: Dick Tump Date: Tue, 21 Jul 2026 09:04:38 +0200 Subject: [PATCH 2/2] Stop ignoring removed spam directory --- .gitignore | 3 --- 1 file changed, 3 deletions(-) diff --git a/.gitignore b/.gitignore index d56f1b5..9dfb0ab 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,3 @@ build/ # Virtual environments .venv/ venv/ - -# Local raw mail (never commit) -/spam/