# email_tunnel Poll Proton Bridge via IMAP and inject messages into a local SMTP server (e.g., Haraka). The script is designed for headless, continuous operation with basic safety/observability baked in. ## What it does - Connects to Proton Bridge IMAP via STARTTLS and selects a required folder. - Polls for new messages by UID, fetches each, and relays it verbatim to a local SMTP server using the original headers. - Strips `Bcc`, deduplicates recipients, and skips malformed addresses. - Tracks progress in a JSON state file so messages are processed once, even across restarts. - Retries IMAP fetch/search and SMTP delivery with bounded attempts/backoff; advances state past permanent delivery failures to avoid loops. - Enforces single-instance execution via a pidfile lock. - Emits scrape-friendly INFO logs each cycle with counts, last UID, and cycle duration. ## Requirements - Python 3.x - Proton Bridge IMAP reachable at the configured host/port - Local SMTP server reachable (e.g., Haraka bound to a non-25 port) ## Configuration (environment variables) - `IMAP_IP` (required): Proton Bridge IMAP host. - `IMAP_PORT` (required): Proton Bridge IMAP port (typically 1143). - `IMAP_USER` (required): IMAP username. - `IMAP_PASSWORD` (required): IMAP password. - `IMAP_FOLDER` (required): IMAP folder to poll; must exist (no fallback). - `IMAP_TLS_VERIFY` (default `1`): Set to `0`/`false` to disable cert/hostname checks (dev only). - `SMTP_IP` (default `127.0.0.1`): SMTP host to deliver to. - `SMTP_PORT` (default `2525`): SMTP port to deliver to. - `POLL_INTERVAL` (default `15`): Seconds between mailbox polls. - `STATE_FILE` (default `./state.json`): Path to persist last processed UID. - `PIDFILE` (default `/tmp/email_tunnel.pid`): Pidfile for single-instance lock. - `LOG_LEVEL` (default `INFO`): Standard logging levels (`DEBUG`, `INFO`, etc.). ## Usage ```bash export IMAP_IP=127.0.0.1 export IMAP_PORT=1143 export IMAP_USER=... export IMAP_PASSWORD=... export IMAP_FOLDER=loomio export SMTP_IP=127.0.0.1 export SMTP_PORT=2525 python3 email_tunnel.py ``` Run under a process supervisor (systemd, supervisord, etc.) so restarts and log rotation are handled. ### Systemd helpers - `email_tunnel.service`: unit file to run the tunnel under systemd (adjust paths/user/group as needed). - `install_email_tunnel.sh`: installs/enables/starts the service, validating `.env` and byte-compiling the script. - `uninstall_email_tunnel.sh`: stops, disables, and removes the service unit. - `logs_email_tunnel.sh`: convenience wrapper around `journalctl` for viewing service logs/status. ## Operational behavior - State tracking: `STATE_FILE` records the last successfully handled UID. It is only advanced after successful delivery, or after a logged `DeliveryError` to avoid reprocessing a permanently failed message. - Retries: IMAP SEARCH/FETCH and SMTP SEND are retried up to 3 times with small backoff. Persistent failures log and move on. - Single instance: pidfile lock prevents multiple concurrent runs; stale pidfiles are replaced if the recorded PID is not running. - Metrics logging: every poll cycle emits a single INFO line with `metrics` prefix and key/value pairs (`cycle_processed`, `cycle_delivered`, `cycle_failed`, `session_*`, `last_uid`, `cycle_duration_ms`). - Missing state: if `STATE_FILE` is absent on startup, the script initializes it to the current max UID (or 0 for an empty mailbox) to avoid reprocessing the entire mailbox. ## Notes and safety - Leave `IMAP_TLS_VERIFY` enabled in production; disable only for trusted, local endpoints. - Ensure the `STATE_FILE` and `PIDFILE` paths are writable by the service user. - If delivering to a server that rejects certain recipients, the script will log the error, advance the UID, and continue. ## Troubleshooting - Increase verbosity with `LOG_LEVEL=DEBUG` to see raw message dumps and IMAP folder listings. - If the script exits immediately, verify required env vars and that `IMAP_FOLDER` exists on the server. - For pidfile conflicts, check the process holding the PID or remove a stale pidfile if no process is running.***