Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and
- Thread output with numbered messages and quoted reply history removed; forwarded emails are kept.
- macOS helper (Swift, native messaging) that puts text and attachments on the clipboard as real files, quarantined
like browser downloads.
- Copy counters on every copy button: how often an email or thread was copied that way, and when last.
- Notes per thread: autosaving note field below the subject that reopens with the thread; toolbar popup lists all
notes with search, link back to Gmail, delete and JSON export. Stored only locally.
- German and English interface.

### Security
Expand Down
5 changes: 5 additions & 0 deletions PRIVACY.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ Paper Clipper for Gmail processes your email only on your own computer.
a local process). The helper writes them to `~/Library/Caches/PaperClipper` and references them on the clipboard.
The most recent copy stays there so that pasting keeps working; older copies are deleted the next time you copy
with attachments (after one hour). `./uninstall.sh` removes the folder.
- Notes are stored in the browser's extension storage (`chrome.storage.local`) on this computer, together with the
subject and the Gmail link of the thread. Copy counters are a local record of which email or thread you copied
and when. Neither is synced or shared. Notes can be deleted and exported in the toolbar popup; counters are
deleted together with the extension.
- Nothing is sent to any server. There are no analytics, no telemetry, no remote code and no third-party libraries.

## Permissions
Expand All @@ -25,6 +29,7 @@ Paper Clipper for Gmail processes your email only on your own computer.
| Access to `mail.google.com` (content script) | show the buttons and load the email you choose to copy |
| `clipboardWrite` | put the text on the clipboard |
| `nativeMessaging` | talk to the local macOS helper for attachments |
| `storage` | keep your notes and copy counters on this computer |

## Contact

Expand Down
16 changes: 15 additions & 1 deletion README.de.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Paper Clipper für Gmail

**Eine Gmail-Mail oder einen ganzen Verlauf mit einem Klick kopieren: Betreff, Absender, Empfänger, Datum und Text.
Auf Wunsch kommen die Anhänge als echte Dateien mit.**
Auf Wunsch kommen die Anhänge als echte Dateien mit. Zu jedem Verlauf kannst du eigene Notizen schreiben.**

Mit ⌘V einfügen in Claude, ChatGPT, Slack, ein Ticket oder den Finder. Die PDFs kommen dabei als PDFs an, nicht als
Textzeile.
Expand All @@ -21,6 +21,10 @@ In Gmail erscheinen zwei Button-Leisten:
| an jeder geöffneten Mail | **Mit Anhängen** | Text und jeder Anhang als Datei |
| unter dem Betreff | **Verlauf kopieren** | alle Mails der Unterhaltung, nummeriert, ohne doppelte Zitate |
| unter dem Betreff | **Verlauf + Anhänge** | der Verlauf und alle Anhänge, jeder nur einmal |
| unter dem Betreff | **Notiz** | öffnet deine Notiz zu diesem Verlauf (siehe [Notizen](#anleitung-notizen)) |

Jeder Kopier-Button zählt, wie oft du diese Mail oder diesen Verlauf damit schon kopiert hast. Die Zahl steht am
Button, der Tooltip zeigt, wann zuletzt. So siehst du sofort, was du schon weitergegeben hast.

Beispiel für **Kopieren**:

Expand Down Expand Up @@ -97,6 +101,16 @@ Gmail neu laden und eine Mail öffnen. Die Buttons stehen unter dem Betreff und
behält den vollen Text.
- Kleine eingebettete Bilder unter 30 KB, meist Signatur-Logos, werden übersprungen. Eingefügte Screenshots kommen mit.

## Anleitung: Notizen

- Unter dem Betreff auf **Notiz** klicken und schreiben. Die Notiz speichert sich beim Tippen von selbst.
- Öffnest du den Verlauf wieder, klappt die Notiz von selbst auf und der Button **Notiz** ist hervorgehoben.
- Text leeren löscht die Notiz.
- Ein Klick auf das Paper-Clipper-Symbol in der Chrome-Symbolleiste zeigt alle Notizen: neueste zuerst, mit Suche,
Link zurück zur Mail, Löschen und **Export** als JSON.
- Notizen und Zähler liegen nur in diesem Browser (`chrome.storage.local`). Sie werden nicht synchronisiert und beim
Entfernen der Erweiterung gelöscht. Vorher exportieren.

## Aktualisieren

```bash
Expand Down
22 changes: 19 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
![Platform: Chrome · macOS](https://img.shields.io/badge/platform-Chrome%20%C2%B7%20macOS-lightgrey)

**Copy a Gmail email or a whole thread in one click: subject, sender, recipients, date and text. The attachments
can come along as real files.**
can come along as real files. Keep private notes on any thread.**

Paste into Claude, ChatGPT, Slack, a ticket or the Finder with ⌘V. The PDFs arrive as PDFs, not as a line of text.

Expand All @@ -24,6 +24,10 @@ Two button bars appear in Gmail:
| every opened email | **With attachments** | text plus every attachment as a file |
| below the subject | **Copy thread** | every email of the conversation, numbered, quoted history removed |
| below the subject | **Thread + attachments** | the thread plus all attachments, each one once |
| below the subject | **Note** | opens your note on this thread (see [Notes](#notes)) |

Each copy button counts how often you copied this email or thread with it. The number sits on the button and the
tooltip shows when you copied it last, so you see at a glance what you already passed on.

Example of **Copy**:

Expand Down Expand Up @@ -100,6 +104,16 @@ Click **With attachments**, switch to the Finder and press ⌘V: the attachments
- Small images embedded in the text, under 30 KB and usually signature logos, are skipped. Pasted screenshots are
kept.

## Notes

- Click **Note** below the subject and type. The note saves itself while you type.
- The next time you open the thread, the note opens by itself and the **Note** button is highlighted.
- Clearing the text deletes the note.
- Click the Paper Clipper icon in the Chrome toolbar to see all notes: newest first, with search, a link back to
the email, delete, and **export** as JSON.
- Notes and counters are stored only in this browser (`chrome.storage.local`). They are not synced and are deleted
when you remove the extension. Export them first.

## Updating

```bash
Expand Down Expand Up @@ -150,7 +164,7 @@ Everything stays on your computer. No server, no analytics, no third-party code.
## Development

```bash
npm test # parser, formatting and version tests (Node ≥ 20, no dependencies)
npm test # parser, formatting, storage and version tests (Node ≥ 20, no dependencies)
npm run build:helper # compile the macOS helper
npm run test:helper # end-to-end helper test (macOS, overwrites the clipboard)
npm run icons # render the icons
Expand All @@ -160,8 +174,10 @@ npm run icons # render the icons

```
manifest.json Manifest V3
src/content.js buttons, notifications, copy flow
src/content.js buttons, counters, notes, notifications, copy flow
src/gmail.js everything Gmail-specific (DOM selectors, raw message URL)
src/store.js counters and notes in chrome.storage.local
src/popup.* toolbar popup with all notes
src/mime.js MIME parser
src/format.js text output, quote stripping, file list
src/background.js relay to the macOS helper
Expand Down
11 changes: 9 additions & 2 deletions _locales/de/messages.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
{
"name": { "message": "Paper Clipper für Gmail" },
"description": { "message": "Kopiert Gmail-Mails und ganze Verläufe mit einem Klick, auf Wunsch mit allen Anhängen als echte Dateien." }
"name": {
"message": "Paper Clipper für Gmail"
},
"description": {
"message": "Kopiert Gmail-Mails und ganze Verläufe mit einem Klick, auf Wunsch mit allen Anhängen als echte Dateien."
},
"actionTitle": {
"message": "Notizen von Paper Clipper"
}
}
11 changes: 9 additions & 2 deletions _locales/en/messages.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
{
"name": { "message": "Paper Clipper for Gmail" },
"description": { "message": "Copy Gmail emails and whole threads in one click, optionally with every attachment as a real file." }
"name": {
"message": "Paper Clipper for Gmail"
},
"description": {
"message": "Copy Gmail emails and whole threads in one click, optionally with every attachment as a real file."
},
"actionTitle": {
"message": "Paper Clipper notes"
}
}
41 changes: 35 additions & 6 deletions manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,44 @@
"description": "__MSG_description__",
"default_locale": "en",
"key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnQMcZNi0VbggiDDt++3oD25hupu42yw+3mLcKLY3oGeZxUiyrcVb9t6b4EKGDHgHTaIuGImPp8CWgPZ6AO10V2lOHcLHcEgr1v8u70QRRluXkUbSK5iXfjW9hrXEoLKYGSaFeP/EF3bO9ZjalLNaqCyLZ18isB9DOyI7kZXe+wDFgklSJ/WgU5ezb4h6ifZRqHEoq+rJN50ZKrfjO0Rb1lpDvXyhLyHjIvmZTy7bdjYp1dXijw9JYkJ+7QqHyMclVann57e487NbPnS6jpIR7t7HztoG6KrpomfCo1w1Q++ebzzI6q4s48sgYpRrlIOGlk9RGe2SpzkvegZfRTvCFQIDAQAB",
"permissions": ["nativeMessaging", "clipboardWrite"],
"background": { "service_worker": "src/background.js" },
"permissions": [
"nativeMessaging",
"clipboardWrite",
"storage"
],
"background": {
"service_worker": "src/background.js"
},
"action": {
"default_title": "__MSG_actionTitle__",
"default_popup": "src/popup.html",
"default_icon": {
"16": "icons/icon16.png",
"32": "icons/icon32.png"
}
},
"content_scripts": [
{
"matches": ["https://mail.google.com/*"],
"js": ["src/mime.js", "src/format.js", "src/gmail.js", "src/content.js"],
"css": ["src/content.css"],
"matches": [
"https://mail.google.com/*"
],
"js": [
"src/mime.js",
"src/format.js",
"src/store.js",
"src/gmail.js",
"src/content.js"
],
"css": [
"src/content.css"
],
"run_at": "document_idle"
}
],
"icons": { "16": "icons/icon16.png", "32": "icons/icon32.png", "48": "icons/icon48.png", "128": "icons/icon128.png" }
"icons": {
"16": "icons/icon16.png",
"32": "icons/icon32.png",
"48": "icons/icon48.png",
"128": "icons/icon128.png"
}
}
61 changes: 61 additions & 0 deletions src/content.css
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@
margin: 8px 0 4px;
}

.paper-clipper-thread > .paper-clipper-bar {
margin: 0;
}

.paper-clipper-btn {
display: inline-flex;
align-items: center;
Expand Down Expand Up @@ -41,6 +45,63 @@
flex: none;
}

.paper-clipper-count {
min-width: 18px;
height: 18px;
margin-left: 2px;
padding: 0 5px;
box-sizing: border-box;
border-radius: 9px;
background: rgba(128, 128, 128, 0.2);
font-size: 11px;
line-height: 18px;
text-align: center;
}

.paper-clipper-count[hidden] {
display: none;
}

.paper-clipper-btn.is-active {
border-color: rgba(227, 116, 0, 0.7);
background: rgba(251, 188, 4, 0.18);
}

.paper-clipper-note {
max-width: 760px;
margin: 8px 0 4px;
}

.paper-clipper-note[hidden] {
display: none;
}

.paper-clipper-note-field {
display: block;
box-sizing: border-box;
width: 100%;
min-height: 76px;
padding: 10px 12px;
border: 1px solid rgba(227, 116, 0, 0.45);
border-radius: 8px;
background: rgba(251, 188, 4, 0.12);
color: inherit;
font: 14px/1.45 'Google Sans', Roboto, Arial, sans-serif;
resize: vertical;
}

.paper-clipper-note-field:focus {
outline: 2px solid #0b57d0;
outline-offset: -1px;
}

.paper-clipper-note-status {
min-height: 16px;
margin-top: 4px;
font: 12px/16px 'Google Sans', Roboto, Arial, sans-serif;
opacity: 0.7;
}

.paper-clipper-busy .paper-clipper-btn {
opacity: 0.5;
cursor: progress;
Expand Down
Loading
Loading