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.
.procmailrc already in place)curl -LsSf https://astral.sh/uv/install.sh | sh)
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
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
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.
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