diff --git a/.gitea/workflows/verify.yml b/.gitea/workflows/verify.yml
new file mode 100644
index 0000000..b84a7cb
--- /dev/null
+++ b/.gitea/workflows/verify.yml
@@ -0,0 +1,39 @@
+name: Verify
+
+on:
+ push:
+ branches: [main]
+ pull_request:
+ workflow_dispatch:
+
+concurrency:
+ group: verify-${{ gitea.repository }}-${{ gitea.ref }}
+ cancel-in-progress: true
+
+permissions:
+ contents: read
+
+jobs:
+ verify:
+ runs-on: ubuntu-latest
+ timeout-minutes: 45
+ env:
+ CI: "true"
+ steps:
+ - uses: actions/checkout@v4
+ - uses: actions/setup-node@v4
+ with:
+ node-version: "22"
+ cache: npm
+ - name: Select declared npm version
+ run: npm install --global npm@11.17.0
+ - name: Install dependencies
+ run: npm ci
+ - name: Audit runtime dependencies
+ run: npm audit --omit=dev --audit-level=moderate
+ - name: Check, test, and build
+ run: npm run check
+ - name: Install browser engines
+ run: npx playwright install --with-deps chromium firefox webkit
+ - name: Browser tests
+ run: npm run test:browser
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 517e3d1..55ea7bc 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,14 @@
# Changelog
+## 0.2.0 - 2026-09-02
+
+- Preserved original message octets and MIME entity ranges, including RFC 2231
+ continued parameters and byte-safe attachment downloads.
+- Added bounded mbox/mboxrd import, threading and search, safe packaged CID-image
+ preview, and deeper MIME-tree redaction with explicit evidence.
+- Added local RSA-SHA256 and Ed25519-SHA256 DKIM verification against public-key
+ DNS text pasted by the user.
+
## 0.1.0 - 2026-09-01
- Initial local-first EML/MIME inspection release.
diff --git a/README.md b/README.md
index 25d60e2..394cc75 100644
--- a/README.md
+++ b/README.md
@@ -1,14 +1,17 @@
# Mail Tools
-Mail Tools is a local-first browser workbench for inspecting `.eml` and MIME
-messages. Version 0.1.0 unfolds headers, decodes RFC 2047 words, builds a bounded
-multipart tree, decodes common transfer encodings, inventories attachments,
-compares text bodies, and creates canonical or focused redacted exports.
+Mail Tools is a local-first browser workbench for inspecting `.eml`, MIME and
+mbox files. It unfolds headers, decodes RFC 2047 words, builds a bounded
+multipart tree, threads mailbox messages, inventories attachments, compares
+text bodies, and creates canonical or focused redacted exports. File imports
+are parsed from their original octets, retain exact source byte ranges for raw
+MIME entities, and assemble RFC 2231 continued parameters.
HTML bodies are sanitized and displayed only in an opaque sandbox with an
embedded `default-src 'none'` policy. Remote images, links, forms, scripts,
-styles, media, frames and active documents are removed. No message, address,
-attachment, URL or telemetry leaves the browser.
+styles, media, frames and active documents are removed. Referenced CID images
+of a small safe type can be embedded from the same message. No message,
+address, attachment, URL or telemetry leaves the browser.
## Development and release
@@ -21,7 +24,7 @@ npm run test:browser
npm run release:artifact
```
-The last command creates deterministic `release/mail-tools-0.1.0.zip` and its
+The last command creates deterministic `release/mail-tools-0.2.0.zip` and its
SHA-256 sidecar. The app uses relative assets and is tested beneath
`/deep/nested/mail/`. It can run standalone or from add·ideas Toolbox.
@@ -29,17 +32,26 @@ SHA-256 sidecar. The app uses relative assets and is tested beneath
- source limit: 8 MiB; at most 2,000 headers, 500 MIME parts, nesting depth 20,
and a conservative 16 MiB decoded-data budget;
-- folded headers, duplicate fields and RFC 2047 B/Q words;
+- folded headers, duplicate fields, RFC 2047 B/Q words, and RFC 2231 parameter
+ continuations;
- multipart and nested `message/rfc822`, Base64 and quoted-printable;
-- safe text previews, sanitized HTML, attachment inventory/download;
-- address/date and unverified SPF/DKIM/DMARC/ARC header diagnostics;
+- bounded mbox/mboxrd import and local Message-ID/References threading;
+- safe text previews, sanitized HTML with local CID images, attachment
+ inventory/download;
+- address/date and SPF/DKIM/DMARC/ARC claim diagnostics;
+- RFC 6376 simple/relaxed RSA-SHA256 and RFC 8463 Ed25519-SHA256 DKIM
+ verification against a public-key TXT record pasted by the user;
- bounded line comparison and normalized EML plus top-level header redaction
with a JSON report.
This is not a mail client, spam detector, forensic verifier or anonymity tool.
-It does not open mailbox containers, contact servers, decrypt S/MIME/OpenPGP,
-validate DKIM signatures, establish sender identity, scan malware, render CID
-resources, or guarantee round-trip byte identity. See
+It does not contact mail or DNS servers, decrypt S/MIME/OpenPGP, establish
+sender identity, scan malware, open maildir/PST/OST containers, or guarantee
+that the deliberately normalized canonical export is byte-identical. DKIM
+verification proves only that the preserved bytes match the pasted key record;
+the tool cannot establish whether that record is authentic or current. The
+untouched source octets remain available for inspection.
+See
[`docs/PRIVACY-SECURITY.md`](docs/PRIVACY-SECURITY.md).
Licensed under GPL-3.0-or-later.
diff --git a/SOURCE.md b/SOURCE.md
index 7c6627e..4d5f069 100644
--- a/SOURCE.md
+++ b/SOURCE.md
@@ -1,8 +1,8 @@
# Corresponding source
-The corresponding source for Mail Tools 0.1.0 is available at:
+The corresponding source for Mail Tools 0.2.0 is available at:
-https://git.add-ideas.de/lotobo/mail-tools/src/tag/v0.1.0
+https://git.add-ideas.de/lotobo/mail-tools/src/tag/v0.2.0
Build with Node.js 22+, npm 11+, and the exact dependencies in
`package-lock.json`. Run `npm ci && npm run release:artifact`.
diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md
index 9102c9a..6676098 100644
--- a/docs/ARCHITECTURE.md
+++ b/docs/ARCHITECTURE.md
@@ -1,11 +1,21 @@
# Architecture
The React shell lazy-loads one workbench. `core/mime.ts` turns bounded source
-text into immutable-looking header and MIME-part records; parsing never creates
-DOM. Transfer decoding consumes a global byte budget. Diagnostics, comparison,
+bytes into immutable-looking header and MIME-part records; parsing never creates
+DOM. A one-byte internal syntax view preserves arbitrary octets, while every raw
+multipart entity records exact offsets into the retained source buffer.
+Transfer decoding consumes a global byte budget. Diagnostics, comparison,
canonicalization and redaction are separate pure modules.
+`core/mbox.ts` splits bounded mbox/mboxrd containers and derives a presentation
+tree from Message-ID, In-Reply-To and References. `core/dkim.ts` implements
+bounded RFC 6376 canonicalization and uses WebCrypto for RSA-SHA256 or
+Ed25519-SHA256 verification. The key record is explicit user input; the app has
+no DNS client and makes no network request.
+
Only the selected HTML text is passed through DOMPurify. It is then embedded in
an iframe without sandbox capabilities and with an inner policy that denies all
-connections and active content. Attachment downloads are explicit Blob URLs
-with sanitized filenames. The service worker caches only same-origin app files.
+connections and active content. Explicit `cid:` image references can resolve to
+small safe image parts already present in the message; no external URI is
+retained. Attachment downloads are explicit Blob URLs with sanitized filenames.
+The service worker caches only same-origin app files.
diff --git a/docs/PRIVACY-SECURITY.md b/docs/PRIVACY-SECURITY.md
index 6b13e96..8300b09 100644
--- a/docs/PRIVACY-SECURITY.md
+++ b/docs/PRIVACY-SECURITY.md
@@ -5,9 +5,16 @@ memory. There is no storage, telemetry, analytics, remote-resource request or
server integration. Closing/reloading the page clears the workbench.
Limits reduce accidental resource exhaustion but do not make Mail Tools a
-forensic parser. HTML loses links, styling and embedded resources by design.
+forensic parser. HTML loses links, styling and external embedded resources by
+design; only bounded safe image parts referenced by `cid:` can be embedded.
Downloaded attachments remain untrusted. Authentication results and Received
-headers are self-asserted text; no DNS or cryptographic verification occurs.
+headers are self-asserted text.
+
+The optional DKIM lab performs local cryptographic verification against a DNS
+TXT value pasted by the user. It never resolves DNS, so a passing result means
+only that the message bytes match that supplied key. It does not prove that the
+key is current, authoritative or obtained securely, and it does not turn other
+authentication headers into verified evidence.
Focused redaction removes a fixed set of top-level transport/authentication
headers. It does not rewrite nested `message/rfc822` content and can leave names,
diff --git a/package-lock.json b/package-lock.json
index 258a5e0..54f359b 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,23 +1,23 @@
{
"name": "mail-tools",
- "version": "0.1.0",
+ "version": "0.2.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "mail-tools",
- "version": "0.1.0",
+ "version": "0.2.0",
"license": "GPL-3.0-or-later",
"dependencies": {
- "@add-ideas/toolbox-contract": "0.2.3",
- "@add-ideas/toolbox-helpers": "0.1.0",
- "@add-ideas/toolbox-shell-react": "0.2.3",
+ "@add-ideas/toolbox-contract": "0.3.0",
+ "@add-ideas/toolbox-helpers": "0.2.0",
+ "@add-ideas/toolbox-shell-react": "0.3.0",
"dompurify": "3.4.14",
"react": "19.2.8",
"react-dom": "19.2.8"
},
"devDependencies": {
- "@add-ideas/toolbox-testkit": "0.2.3",
+ "@add-ideas/toolbox-testkit": "0.3.0",
"@eslint/js": "10.0.1",
"@playwright/test": "1.62.1",
"@testing-library/jest-dom": "6.9.1",
@@ -43,24 +43,24 @@
}
},
"node_modules/@add-ideas/toolbox-contract": {
- "version": "0.2.3",
- "resolved": "https://git.add-ideas.de/api/packages/lotobo/npm/%40add-ideas%2Ftoolbox-contract/-/0.2.3/toolbox-contract-0.2.3.tgz",
- "integrity": "sha512-T0PVSuMT40GjTDfQJhEEY3ZawQq8zz1/ry95JdKI6W39CdLacaRXdGnEpDCMHt+jUbf1Jz7Nat/M5dFCgKVM9A==",
+ "version": "0.3.0",
+ "resolved": "https://git.add-ideas.de/api/packages/lotobo/npm/%40add-ideas%2Ftoolbox-contract/-/0.3.0/toolbox-contract-0.3.0.tgz",
+ "integrity": "sha512-dKrK7BjOFwqJaBfJuhKxZKIld4sH0AKjEn6a0yLnbdMUFY+fFv4VSLGV2tNSBD016gumc2iNqOjUj/ld7x4rtA==",
"license": "Apache-2.0"
},
"node_modules/@add-ideas/toolbox-helpers": {
- "version": "0.1.0",
- "resolved": "https://git.add-ideas.de/api/packages/lotobo/npm/%40add-ideas%2Ftoolbox-helpers/-/0.1.0/toolbox-helpers-0.1.0.tgz",
- "integrity": "sha512-UKl1Oxekedf8D2df86VrnVA53AcMhrnh6iUPXY+k8frirBXotb0yd8SGT+IF/3hcqYwcYe/v9WVFuSgKtIYVnw==",
+ "version": "0.2.0",
+ "resolved": "https://git.add-ideas.de/api/packages/lotobo/npm/%40add-ideas%2Ftoolbox-helpers/-/0.2.0/toolbox-helpers-0.2.0.tgz",
+ "integrity": "sha512-SdOqkw+P+3J3fa5iVkzb5P15rVepB001GNV21Oh8w0CZcVL+YRltgD/s+MVcTyrNijWQf3E5vtQON/3N2LLyKg==",
"license": "GPL-3.0-or-later"
},
"node_modules/@add-ideas/toolbox-shell-react": {
- "version": "0.2.3",
- "resolved": "https://git.add-ideas.de/api/packages/lotobo/npm/%40add-ideas%2Ftoolbox-shell-react/-/0.2.3/toolbox-shell-react-0.2.3.tgz",
- "integrity": "sha512-DT5lQDH48BFkFcmFLZnQh7+Cm73JzBPcmp5WzUXypfkUXpEyDYHzaXgmW4kZ0edSwh4RK4sPmx+JPtK0X4aKCQ==",
+ "version": "0.3.0",
+ "resolved": "https://git.add-ideas.de/api/packages/lotobo/npm/%40add-ideas%2Ftoolbox-shell-react/-/0.3.0/toolbox-shell-react-0.3.0.tgz",
+ "integrity": "sha512-74p6JzAOG0YCAKdlc1hLofV4ZIko7vb448S75cIiM88PKm93EHl5VD7g8YVyfM56Ui97UY9dmy+Whiq4sGzpsg==",
"license": "Apache-2.0",
"dependencies": {
- "@add-ideas/toolbox-contract": "0.2.3"
+ "@add-ideas/toolbox-contract": "0.3.0"
},
"peerDependencies": {
"react": ">=18 <20",
@@ -68,13 +68,13 @@
}
},
"node_modules/@add-ideas/toolbox-testkit": {
- "version": "0.2.3",
- "resolved": "https://git.add-ideas.de/api/packages/lotobo/npm/%40add-ideas%2Ftoolbox-testkit/-/0.2.3/toolbox-testkit-0.2.3.tgz",
- "integrity": "sha512-sq1MwhKWfFKen+N+124hl74qQimRSvmQ9sOU7jdcI+2qCKZ67+2B8rWyezeV80uTFu4Jv6deHksfYQ/tKNV6XQ==",
+ "version": "0.3.0",
+ "resolved": "https://git.add-ideas.de/api/packages/lotobo/npm/%40add-ideas%2Ftoolbox-testkit/-/0.3.0/toolbox-testkit-0.3.0.tgz",
+ "integrity": "sha512-4Fk+oSvZFspOMIXr8Xy040nhAaBsIQAzsGyXWSpjn3+k3yBKq7nB1r5zCHhsXzfdLzvPDAx2KcmSNOhM330D9w==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@add-ideas/toolbox-contract": "0.2.3"
+ "@add-ideas/toolbox-contract": "0.3.0"
},
"bin": {
"toolbox-check": "dist/cli.js"
diff --git a/package.json b/package.json
index 1a57a3f..45a599d 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "mail-tools",
- "version": "0.1.0",
+ "version": "0.2.0",
"description": "Inspect, compare, redact and export email messages locally in the browser.",
"license": "GPL-3.0-or-later",
"author": "Albrecht Degering",
@@ -39,15 +39,15 @@
"release:artifact": "npm run check && npm run test:browser && npm run package:release -- --force"
},
"dependencies": {
- "@add-ideas/toolbox-contract": "0.2.3",
- "@add-ideas/toolbox-helpers": "0.1.0",
- "@add-ideas/toolbox-shell-react": "0.2.3",
+ "@add-ideas/toolbox-contract": "0.3.0",
+ "@add-ideas/toolbox-helpers": "0.2.0",
+ "@add-ideas/toolbox-shell-react": "0.3.0",
"dompurify": "3.4.14",
"react": "19.2.8",
"react-dom": "19.2.8"
},
"devDependencies": {
- "@add-ideas/toolbox-testkit": "0.2.3",
+ "@add-ideas/toolbox-testkit": "0.3.0",
"@eslint/js": "10.0.1",
"@playwright/test": "1.62.1",
"@testing-library/jest-dom": "6.9.1",
diff --git a/playwright.config.ts b/playwright.config.ts
index 2ec09cb..f59c348 100644
--- a/playwright.config.ts
+++ b/playwright.config.ts
@@ -15,7 +15,25 @@ export default defineConfig({
timeout: 180_000,
},
projects: [
- { name: "chromium", use: { ...devices["Desktop Chrome"] } },
- { name: "firefox", use: { ...devices["Desktop Firefox"] } },
+ {
+ name: "chromium",
+ testIgnore: /responsive\.spec\.ts/,
+ use: { ...devices["Desktop Chrome"] },
+ },
+ {
+ name: "firefox",
+ testIgnore: /responsive\.spec\.ts/,
+ use: { ...devices["Desktop Firefox"] },
+ },
+ {
+ name: "webkit",
+ testIgnore: /responsive\.spec\.ts/,
+ use: { ...devices["Desktop Safari"] },
+ },
+ {
+ name: "mobile-chromium",
+ testMatch: /responsive\.spec\.ts/,
+ use: { ...devices["Pixel 5"] },
+ },
],
});
diff --git a/public/CHANGELOG.md b/public/CHANGELOG.md
index 517e3d1..55ea7bc 100644
--- a/public/CHANGELOG.md
+++ b/public/CHANGELOG.md
@@ -1,5 +1,14 @@
# Changelog
+## 0.2.0 - 2026-09-02
+
+- Preserved original message octets and MIME entity ranges, including RFC 2231
+ continued parameters and byte-safe attachment downloads.
+- Added bounded mbox/mboxrd import, threading and search, safe packaged CID-image
+ preview, and deeper MIME-tree redaction with explicit evidence.
+- Added local RSA-SHA256 and Ed25519-SHA256 DKIM verification against public-key
+ DNS text pasted by the user.
+
## 0.1.0 - 2026-09-01
- Initial local-first EML/MIME inspection release.
diff --git a/public/LICENSES/npm-runtime-licenses.txt b/public/LICENSES/npm-runtime-licenses.txt
index 790670c..02895b7 100644
--- a/public/LICENSES/npm-runtime-licenses.txt
+++ b/public/LICENSES/npm-runtime-licenses.txt
@@ -1,5 +1,5 @@
==============================================================================
-@add-ideas/toolbox-contract@0.2.3
+@add-ideas/toolbox-contract@0.3.0
Declared licence: Apache-2.0
==============================================================================
--- LICENSE ---
@@ -198,7 +198,7 @@ Declared licence: Apache-2.0
==============================================================================
-@add-ideas/toolbox-helpers@0.1.0
+@add-ideas/toolbox-helpers@0.2.0
Declared licence: GPL-3.0-or-later
==============================================================================
--- LICENSE ---
@@ -879,7 +879,7 @@ Public License instead of this License. But first, please read
==============================================================================
-@add-ideas/toolbox-shell-react@0.2.3
+@add-ideas/toolbox-shell-react@0.3.0
Declared licence: Apache-2.0
==============================================================================
--- LICENSE ---
diff --git a/public/README.md b/public/README.md
index 25d60e2..394cc75 100644
--- a/public/README.md
+++ b/public/README.md
@@ -1,14 +1,17 @@
# Mail Tools
-Mail Tools is a local-first browser workbench for inspecting `.eml` and MIME
-messages. Version 0.1.0 unfolds headers, decodes RFC 2047 words, builds a bounded
-multipart tree, decodes common transfer encodings, inventories attachments,
-compares text bodies, and creates canonical or focused redacted exports.
+Mail Tools is a local-first browser workbench for inspecting `.eml`, MIME and
+mbox files. It unfolds headers, decodes RFC 2047 words, builds a bounded
+multipart tree, threads mailbox messages, inventories attachments, compares
+text bodies, and creates canonical or focused redacted exports. File imports
+are parsed from their original octets, retain exact source byte ranges for raw
+MIME entities, and assemble RFC 2231 continued parameters.
HTML bodies are sanitized and displayed only in an opaque sandbox with an
embedded `default-src 'none'` policy. Remote images, links, forms, scripts,
-styles, media, frames and active documents are removed. No message, address,
-attachment, URL or telemetry leaves the browser.
+styles, media, frames and active documents are removed. Referenced CID images
+of a small safe type can be embedded from the same message. No message,
+address, attachment, URL or telemetry leaves the browser.
## Development and release
@@ -21,7 +24,7 @@ npm run test:browser
npm run release:artifact
```
-The last command creates deterministic `release/mail-tools-0.1.0.zip` and its
+The last command creates deterministic `release/mail-tools-0.2.0.zip` and its
SHA-256 sidecar. The app uses relative assets and is tested beneath
`/deep/nested/mail/`. It can run standalone or from add·ideas Toolbox.
@@ -29,17 +32,26 @@ SHA-256 sidecar. The app uses relative assets and is tested beneath
- source limit: 8 MiB; at most 2,000 headers, 500 MIME parts, nesting depth 20,
and a conservative 16 MiB decoded-data budget;
-- folded headers, duplicate fields and RFC 2047 B/Q words;
+- folded headers, duplicate fields, RFC 2047 B/Q words, and RFC 2231 parameter
+ continuations;
- multipart and nested `message/rfc822`, Base64 and quoted-printable;
-- safe text previews, sanitized HTML, attachment inventory/download;
-- address/date and unverified SPF/DKIM/DMARC/ARC header diagnostics;
+- bounded mbox/mboxrd import and local Message-ID/References threading;
+- safe text previews, sanitized HTML with local CID images, attachment
+ inventory/download;
+- address/date and SPF/DKIM/DMARC/ARC claim diagnostics;
+- RFC 6376 simple/relaxed RSA-SHA256 and RFC 8463 Ed25519-SHA256 DKIM
+ verification against a public-key TXT record pasted by the user;
- bounded line comparison and normalized EML plus top-level header redaction
with a JSON report.
This is not a mail client, spam detector, forensic verifier or anonymity tool.
-It does not open mailbox containers, contact servers, decrypt S/MIME/OpenPGP,
-validate DKIM signatures, establish sender identity, scan malware, render CID
-resources, or guarantee round-trip byte identity. See
+It does not contact mail or DNS servers, decrypt S/MIME/OpenPGP, establish
+sender identity, scan malware, open maildir/PST/OST containers, or guarantee
+that the deliberately normalized canonical export is byte-identical. DKIM
+verification proves only that the preserved bytes match the pasted key record;
+the tool cannot establish whether that record is authentic or current. The
+untouched source octets remain available for inspection.
+See
[`docs/PRIVACY-SECURITY.md`](docs/PRIVACY-SECURITY.md).
Licensed under GPL-3.0-or-later.
diff --git a/public/SOURCE.md b/public/SOURCE.md
index 7c6627e..4d5f069 100644
--- a/public/SOURCE.md
+++ b/public/SOURCE.md
@@ -1,8 +1,8 @@
# Corresponding source
-The corresponding source for Mail Tools 0.1.0 is available at:
+The corresponding source for Mail Tools 0.2.0 is available at:
-https://git.add-ideas.de/lotobo/mail-tools/src/tag/v0.1.0
+https://git.add-ideas.de/lotobo/mail-tools/src/tag/v0.2.0
Build with Node.js 22+, npm 11+, and the exact dependencies in
`package-lock.json`. Run `npm ci && npm run release:artifact`.
diff --git a/public/docs/ARCHITECTURE.md b/public/docs/ARCHITECTURE.md
index 9102c9a..6676098 100644
--- a/public/docs/ARCHITECTURE.md
+++ b/public/docs/ARCHITECTURE.md
@@ -1,11 +1,21 @@
# Architecture
The React shell lazy-loads one workbench. `core/mime.ts` turns bounded source
-text into immutable-looking header and MIME-part records; parsing never creates
-DOM. Transfer decoding consumes a global byte budget. Diagnostics, comparison,
+bytes into immutable-looking header and MIME-part records; parsing never creates
+DOM. A one-byte internal syntax view preserves arbitrary octets, while every raw
+multipart entity records exact offsets into the retained source buffer.
+Transfer decoding consumes a global byte budget. Diagnostics, comparison,
canonicalization and redaction are separate pure modules.
+`core/mbox.ts` splits bounded mbox/mboxrd containers and derives a presentation
+tree from Message-ID, In-Reply-To and References. `core/dkim.ts` implements
+bounded RFC 6376 canonicalization and uses WebCrypto for RSA-SHA256 or
+Ed25519-SHA256 verification. The key record is explicit user input; the app has
+no DNS client and makes no network request.
+
Only the selected HTML text is passed through DOMPurify. It is then embedded in
an iframe without sandbox capabilities and with an inner policy that denies all
-connections and active content. Attachment downloads are explicit Blob URLs
-with sanitized filenames. The service worker caches only same-origin app files.
+connections and active content. Explicit `cid:` image references can resolve to
+small safe image parts already present in the message; no external URI is
+retained. Attachment downloads are explicit Blob URLs with sanitized filenames.
+The service worker caches only same-origin app files.
diff --git a/public/docs/PRIVACY-SECURITY.md b/public/docs/PRIVACY-SECURITY.md
index 6b13e96..8300b09 100644
--- a/public/docs/PRIVACY-SECURITY.md
+++ b/public/docs/PRIVACY-SECURITY.md
@@ -5,9 +5,16 @@ memory. There is no storage, telemetry, analytics, remote-resource request or
server integration. Closing/reloading the page clears the workbench.
Limits reduce accidental resource exhaustion but do not make Mail Tools a
-forensic parser. HTML loses links, styling and embedded resources by design.
+forensic parser. HTML loses links, styling and external embedded resources by
+design; only bounded safe image parts referenced by `cid:` can be embedded.
Downloaded attachments remain untrusted. Authentication results and Received
-headers are self-asserted text; no DNS or cryptographic verification occurs.
+headers are self-asserted text.
+
+The optional DKIM lab performs local cryptographic verification against a DNS
+TXT value pasted by the user. It never resolves DNS, so a passing result means
+only that the message bytes match that supplied key. It does not prove that the
+key is current, authoritative or obtained securely, and it does not turn other
+authentication headers into verified evidence.
Focused redaction removes a fixed set of top-level transport/authentication
headers. It does not rewrite nested `message/rfc822` content and can leave names,
diff --git a/public/sw.js b/public/sw.js
index 42529c2..7fdc32b 100644
--- a/public/sw.js
+++ b/public/sw.js
@@ -1,5 +1,5 @@
const CACHE_PREFIX = "mail-tools-shell-";
-const CACHE_NAME = CACHE_PREFIX + "0.1.0";
+const CACHE_NAME = CACHE_PREFIX + "0.2.0";
const CORE = [
"./",
"./manifest.webmanifest",
diff --git a/public/toolbox-app.json b/public/toolbox-app.json
index c5e5fbc..4560b88 100644
--- a/public/toolbox-app.json
+++ b/public/toolbox-app.json
@@ -3,12 +3,12 @@
"schemaVersion": 1,
"id": "de.add-ideas.mail-tools",
"name": "Mail Tools",
- "version": "0.1.0",
- "description": "Inspect and redact email messages locally.",
+ "version": "0.2.0",
+ "description": "Inspect email and mailbox files locally.",
"entry": "./",
"icon": "./favicon.svg",
"categories": ["documents", "developer", "privacy"],
- "tags": ["email", "eml", "mime", "headers", "attachments"],
+ "tags": ["email", "eml", "mbox", "mime", "dkim", "attachments"],
"integration": {
"contextVersion": 1,
"launchModes": ["navigate", "new-tab"],
@@ -21,6 +21,18 @@
"crossOriginIsolated": false,
"topLevelContext": false
},
+ "io": {
+ "accepts": [
+ { "mediaType": "message/rfc822", "extensions": [".eml"] },
+ { "mediaType": "application/mbox", "extensions": [".mbox", ".mbx"] },
+ { "mediaType": "text/plain", "extensions": [".txt"] }
+ ],
+ "produces": [
+ { "mediaType": "message/rfc822", "extensions": [".eml"] },
+ { "mediaType": "application/json", "extensions": [".json"] }
+ ]
+ },
+ "capabilities": { "required": [], "optional": ["web-crypto"] },
"privacy": {
"processing": "local",
"fileUploads": true,
diff --git a/src/components/HelpDialog.tsx b/src/components/HelpDialog.tsx
index b0b8233..0cbcb87 100644
--- a/src/components/HelpDialog.tsx
+++ b/src/components/HelpDialog.tsx
@@ -32,16 +32,20 @@ export function HelpDialog({
- Open EML/MIME source, inspect its header and multipart structure,
- compare body parts, save attachments, and make focused redacted copies.
+ Open EML/MIME source or a bounded mbox, inspect its header and multipart
+ structure, compare body parts, save attachments, and make focused
+ redacted copies.
Parsing is bounded and entirely local. HTML is sanitized and shown in an
opaque sandbox whose own policy blocks every network request.
- Authentication headers are unverified claims. Redaction removes selected
- transport/authentication headers only; it is not an anonymity guarantee.
+ Authentication headers remain claims. The DKIM lab can verify preserved
+ bytes against a public-key TXT record you paste, but deliberately makes
+ no DNS request and cannot authenticate that key. Redaction removes
+ selected transport/authentication headers only; it is not an anonymity
+ guarantee.
+ Threading uses only Message-ID, In-Reply-To and References from
+ messages already present in this local file. Envelope separators
+ and mailbox contents are never contacted or executed.
+
Reported SPF, DKIM, DMARC and ARC results are displayed as
- claims, never re-verified.
+ claims. The optional DKIM lab verifies a signature only against
+ a public-key record you paste locally.
- Removes {redacted.removed.length} top-level
- transport/authentication header fields. It does not scan nested
- messages, bodies or attachments for personal data.
+ Removes {redacted.removedHeaders.length} selected header field
+ {redacted.removedHeaders.length === 1 ? "" : "s"} throughout the
+ MIME tree. Optional destructive policies can replace decoded text
+ bodies and attachment payloads.