A Roundcube (Elastic skin) plugin to attach documents from a Paperless-ngx instance straight from the compose window — search, filter, pick, attached. No download/re-upload detour. The per-user API token is stored encrypted and all Paperless traffic stays server-side.
- 🔍 Search + filter your documents — full-text, tags, correspondent, document type, date range — and multi-select across pages.
- 🖇️ Attaches the searchable archive PDF, fetched server-side.
- 🔐 Token stored encrypted; token + Paperless URL never reach the browser (single server-side proxy).
- 🧰 Oversize rejected before download, born-digital docs skipped, per-item batch results, no duplicate attaches.
- 🐳 Survives
:latest(bind-mount +ROUNDCUBEMAIL_PLUGINS, no image build).
| Compose button | Settings — token + connection test |
|---|---|
![]() |
![]() |
Document titles, correspondents and the sender address are blurred in the screenshots.
Roundcube 1.6.x · Elastic skin only · PHP 7.4+ · a reachable Paperless-ngx instance.
Composer (from your Roundcube root):
composer require dodjango/paperless_attachDocker bind-mount (recommended for roundcube/roundcubemail:latest — survives image updates):
services:
roundcubemail:
volumes:
- ./plugins/paperless_attach:/var/www/html/plugins/paperless_attach:ro
environment:
- ROUNDCUBEMAIL_PLUGINS=archive,zipdownload,...,paperless_attach # append, keep the rest
- ROUNDCUBEMAIL_DES_KEY=<EXACTLY 24 characters> # encrypts the tokenSet PHP upload_max_filesize / post_max_size / memory_limit ≥ your Roundcube upload limit, otherwise the effective attachment cap drops to the lower value.
⚠️ Never changedes_keyafter tokens are stored — it makes all stored tokens (and sessions) undecryptable; every user would have to re-enter their token. Pin it once.
- Token (per user): Settings → Paperless → paste your Paperless API token → Save → Test connection.
- Paperless URL (server-side): copy
config.inc.php.dist→config.inc.phpand set$config['paperless_url']. It is server-fixed (SSRF guard — no per-user URL field); the defaulthttp://paperless-webserver:8000is an internal Docker hostname, so most installs must change it.
Token encrypted via rcube::encrypt() — never stored in DB plaintext, echoed to the field, or placed in rcmail.env/AJAX. All Paperless calls originate from one server-side proxy (lib/PaperlessClient.php) with redirects disabled, enforced timeouts, and integer-validated document ids. Designed for internal-network use.
v1.0 — in daily use on the author's self-hosted stack. Best-effort community plugin (no warranty), so far verified on a single deployment; testing on other Roundcube 1.6.x setups, issues and PRs are very welcome.
Conventional Commits + Semantic Versioning, released automatically via release-please. See CONTRIBUTING.md.
Archive-vs-original choice per document · inline PDF preview · saved searches · skins other than Elastic.
Created and maintained by @dodjango. Built with the help of AI tooling (Claude); all code is human-reviewed and live-tested.
Licensed under GPL-3.0-or-later — see LICENSE.


