Configuring Paperless-ngx to monitor emails from a Proton Mail account

/ Reading time: 6 minute/s

I've been setting up a Paperless-ngx instance on my homelab as part of my 2024 resolution to immerse myself more into managing a baremetal server. One of the things I want it to do is to monitor my email inbox for documents I receive regularly (think bills, receipts, etc.) so that they are automatically fetched into the digital archive.

However, I use Proton Mail, and as part of their security measures, they don't provide direct access to their IMAP or SMTP servers like how you'd expect with most email providers. I do appreciate this, but it does make it difficult to hook up Paperless-ngx to monitor my mail.

How I got it to work

Proton does provide a bridge that connects to their servers on your behalf, and exposes an IMAP and SMTP server that you can connect to. Simply put, this acts like a middleman between your email client and Proton's servers.

However, the bridge has a hard requirement to only accept connections from 127.0.0.1 (or localhost). This is a problem since I run my Paperless-ngx stack in a Docker container as part of a Compose stack, so network packets from the container will look like they're coming from somewhere external to my server, even though they're actually running in the same machine. This is complicated even more by a requirement I have to maintain a separate network for my containers, so the bridge and my apps aren't even going to be running in the same network.

An interesting project I came across is the ProtonMail IMAP/SMTP Bridge Docker Container, which wraps the bridge in a Docker container. But the real magic it does is that it uses socat to forward network packets the container receives to the actual ports the bridge is listening on. This will make it appear to the bridge that the packets are coming from localhost.

So making the two containers work together can be as simple as:

networks:
  my-network:
    # ...

services:
  paperless:
    image: ghcr.io/paperless-ngx/paperless-ngx:latest
    restart: unless-stopped
    networks:
      - my-network

  proton-bridge:
    image: shenxn/protonmail-bridge-docker:latest
    restart: unless-stopped
    networks:
      - my-network

The bridge will be visible to the Paperless-ngx container via host name proton-bridge, and will be listening on the default ports 25 and 143 (not 1025 and 1143).

Successful connection
I have to admit it took me too long to finally get this working

Caveats

One very obvious consideration you have to make is that you're potentially exposing your Proton Mail inbox to more consumers than what it was originally designed for. There's tons of discussion on this topic online, so I'm not going to go into that here. What you should know is that by doing this, any other entity in the my-network network can potentially read your emails.

Another thing I had to do was patch the bridge container so that the base build image uses golang:1.20 instead of what it's currently using. I haven't dived too deeply into it, but the current master on project does not build, since the Proton bridge codebase now seems to require at least Go 1.20.

Finally, when registering the IMAP server to Paperless-ngx through the web UI, I couldn't get it to connect successfully with either SSL or STARTTLS. You might have noticed that the connection above had No encryption set.

If you go through the steps to register your Proton Mail account to the bridge, you'll confirm that the bridge does protect the IMAP server using STARTTLS. I should investigate this further, but it may be that this is a side effect of using socat to route network packets to the bridge.