<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Bernhard</title>
    <description>The latest articles on DEV Community by Bernhard (@loopology).</description>
    <link>https://dev.to/loopology</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3822165%2F78abc2c0-71f1-434c-a19e-ce8796ee1125.jpeg</url>
      <title>DEV Community: Bernhard</title>
      <link>https://dev.to/loopology</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/loopology"/>
    <language>en</language>
    <item>
      <title>Replacing Gmail's "fetch mail from other accounts" with procmail + IMAP</title>
      <dc:creator>Bernhard</dc:creator>
      <pubDate>Tue, 17 Mar 2026 11:20:07 +0000</pubDate>
      <link>https://dev.to/loopology/replacing-gmails-fetch-mail-from-other-accounts-with-procmail-imap-22bg</link>
      <guid>https://dev.to/loopology/replacing-gmails-fetch-mail-from-other-accounts-with-procmail-imap-22bg</guid>
      <description>&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;For years, Gmail offered a convenient feature: it could &lt;a href="https://support.google.com/mail/answer/21289" rel="noopener noreferrer"&gt;periodically fetch mail from an external account (POP3)&lt;/a&gt; and deliver it to your Gmail inbox. In 2025, Google &lt;a href="https://support.google.com/mail/answer/16604719" rel="noopener noreferrer"&gt;announced it would discontinue this feature&lt;/a&gt;. If your mail lives on a server you can ssh into here's an alternative.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Shell access (SSH) to the mail server where your mail arrives
procmail installed and active on that server (a .procmailrc already in place)&lt;/li&gt;
&lt;li&gt;A Gmail account with IMAP enabled&lt;/li&gt;
&lt;li&gt;A Gmail &lt;a href="https://myaccount.google.com/apppasswords" rel="noopener noreferrer"&gt;App Password&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.astral.sh/uv/" rel="noopener noreferrer"&gt;uv&lt;/a&gt; installed on the mail server (single-user &lt;a href="https://github.com/astral-sh/uv?tab=readme-ov-file#installation" rel="noopener noreferrer"&gt;install&lt;/a&gt;, no root required)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Script
&lt;/h2&gt;

&lt;p&gt;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 &lt;code&gt;~/.config/mailsync/config&lt;/code&gt; (mode 600).&lt;/p&gt;

&lt;p&gt;Source code: &lt;a href="//github.com/bwagner/gmailsync"&gt;github.com/bwagner/gmailsync&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;p&gt;Copy the script to &lt;code&gt;~/bin/upload_eml.py&lt;/code&gt; on your mail server, make it executable, then save your credentials:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;chmod&lt;/span&gt; +x ~/bin/upload_eml.py
~/bin/upload_eml.py &lt;span class="nt"&gt;--save-credentials&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The procmail Recipe
&lt;/h2&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;/.local/bin:&lt;span class="nv"&gt;$PATH&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Upload a copy to Gmail via IMAP
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;:0 c
| $HOME/bin/upload_eml.py -

## Deliver the original to local Maildir
:0
$HOME/Maildir/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;:0 c&lt;/code&gt; 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 &lt;code&gt;:0 c&lt;/code&gt; to &lt;code&gt;:0&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing
&lt;/h2&gt;

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

&lt;p&gt;&lt;code&gt;~/bin/upload_eml.py --fake-id /path/to/message.eml&lt;/code&gt;&lt;br&gt;
Use &lt;code&gt;--fake-id&lt;/code&gt; to force a duplicate upload (useful for verifying that the upload works, since Gmail deduplicates messages by Message-ID).&lt;/p&gt;

</description>
      <category>automation</category>
      <category>linux</category>
      <category>python</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
