A bash script that downloads email attachments from a Proton Mail label via Proton Mail Bridge, saves them locally with optional date prefixing, and re-labels processed emails. Emails without matching attachments can be unlabelled separately.
- Proton Mail Bridge installed and running
python3(stdlib only — no pip installs required)
git clone https://github.com/youruser/proton-fetch-attachments.git
cd proton-fetch-attachments
cp .env.example .envEdit .env with your values, then make the script executable:
chmod +x proton_fetch_attachments.shAll configuration lives in .env, which is sourced automatically at startup. .env is listed in .gitignore and will never be committed.
Copy .env.example to .env to get started. Variables set in the shell environment take precedence over .env, which takes precedence over the script's built-in defaults.
| Variable | Default | Description |
|---|---|---|
IMAP_HOST |
127.0.0.1 |
Bridge IMAP host |
IMAP_PORT |
1143 |
Bridge IMAP port — verify in the Bridge UI |
IMAP_USER |
— | Your Proton address as shown in Bridge |
IMAP_PASS |
— | The Bridge-generated password (not your Proton login) |
SOURCE_LABEL |
— | Label to scan, e.g. Labels/invoices |
DONE_LABEL |
— | Label to apply after processing, e.g. Labels/invoices-processed |
OUTPUT_DIR |
~/Documents/Attachments |
Local folder to save attachments into |
FILE_EXTENSIONS |
pdf |
Comma-separated extensions to fetch, e.g. pdf,docx,xlsx |
DATE_PREFIX |
1 |
Prepend received date to filename: 1 = yes, 0 = no |
DATE_FORMAT |
%Y.%m.%d |
Date format (strftime) — e.g. 2026.04.10_filename.pdf |
SANITISE_FILENAME |
1 |
Strip problematic characters from filename: 1 = yes, 0 = keep original |
INCLUDE_SENDER |
1 |
Include sender display name in filename: 1 = yes, 0 = no. Name is truncated to 25 characters, spaces replaced with -, non-alphanumeric characters stripped |
Proton Mail Bridge exposes labels over IMAP with a Labels/ prefix. If your label in Proton is called invoices, the correct value for SOURCE_LABEL is Labels/invoices. Run the script once with a non-existent label to get a list of all available folder names printed to stdout.
./proton_fetch_attachments.sh [--dry-run] [--unlabel-skipped]
--dry-run
Preview all actions without writing any files or changing any labels. Recommended on first run.
--unlabel-skipped
Instead of processing emails with matching attachments, remove the source label from emails that have no matching attachment. Emails with matching attachments are ignored. The two modes are mutually exclusive in effect; combine with --dry-run to preview.
# Preview what would be processed
./proton_fetch_attachments.sh --dry-run
# Download attachments and re-label processed emails
./proton_fetch_attachments.sh
# Preview which emails without attachments would be unlabelled
./proton_fetch_attachments.sh --dry-run --unlabel-skipped
# Remove source label from emails without matching attachments
./proton_fetch_attachments.sh --unlabel-skipped
# Override output directory for a single run
OUTPUT_DIR=~/Desktop ./proton_fetch_attachments.sh --dry-run- Connects to Proton Mail Bridge over IMAP on localhost
- Selects the source label and takes a snapshot of all message IDs at that moment — emails arriving during the run are ignored
- For each message in the snapshot:
- In normal mode: downloads attachments with matching extensions, saves them to
OUTPUT_DIR, then moves the email to the done label - In
--unlabel-skippedmode: removes the source label from emails with no matching attachment; ignores emails that do have one
- In normal mode: downloads attachments with matching extensions, saves them to
- Filenames are optionally prefixed with the email's received date and sanitised to remove characters that are problematic on most filesystems
- If a file with the same name already exists, a numeric counter is appended rather than overwriting
The script does not delete emails. Re-labelling works by copying the message to the done label (adding that label) and then flagging it as deleted in the source folder only, followed by an expunge scoped to that folder. This removes the source label while leaving the email intact under the done label.
- The Bridge-generated IMAP password is different from your Proton account password. Find it in the Bridge UI under your account.
- Bridge must be running before the script is executed. It does not attempt to start Bridge automatically.
- No third-party Python packages are required.