local_email_bridge/README.md

3.6 KiB

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

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.

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.***