Replacing Gmail's "fetch mail from another account" with procmail + IMAP

The Problem

For years, Gmail offered a convenient feature: it could periodically fetch mail from an external account (POP3) and deliver it to your Gmail inbox. In 2025, Google announced it would discontinue this feature. If your mail lives on a server you can ssh into here's an alternative.

This post describes a simple replacement: whenever mail arrives on the remote server, a procmail recipe pipes it to a small Python script that uploads it to Gmail via IMAP.

Prerequisites

The Script

The script upload_eml.py reads a mail message (from a file or stdin), and uploads it to Gmail via IMAP, preserving the original date. Credentials are stored in ~/.config/mailsync/config (mode 600).

Source code: github.com/bwagner/gmailsync

Setup

Copy the script to ~/bin/upload_eml.py on your mail server, make it executable, then save your credentials:

chmod +x ~/bin/upload_eml.py
~/bin/upload_eml.py --save-credentials

The procmail Recipe

Add the following to the end of your .procmailrc, before the final #### End Processing section #### comment. Make sure ~/.local/bin (where uv lives) is in your PATH.

PATH=$HOME/.local/bin:$PATH

# Upload a copy to Gmail via IMAP
:0 c
| $HOME/bin/upload_eml.py -

# Deliver the original to local Maildir
:0
$HOME/Maildir/

The :0 c flag makes a copy for the pipe while the original falls through to local delivery. Once you are confident the setup is reliable and Gmail is no longer fetching in parallel, you can drop the local copy by removing the second recipe and changing :0 c to :0.

Testing

You can test the script manually against an .eml file (in Gmail, open a message, click the three dots top right, choose "Download message"):

~/bin/upload_eml.py /path/to/message.eml

Use --fake-id to force a duplicate upload (useful for verifying that the upload works, since Gmail deduplicates messages by Message-ID):

~/bin/upload_eml.py --fake-id /path/to/message.eml

xmlizer.net