Replacing Gmail’s POP3 import with go-imapproc

For years, I have been using Gmail’s “Check mail from other accounts” feature to pull in e-mails from my GMX address and my personal mail server into my Gmail inbox. Simple, reliable, and totally invisible once set up. In the times of SPF, DMARC, and what-not-else, simply forwarding e-mails to another address is just not really reliable any more.

Then came the e-mail from Google. Google is deprecating the POP3 import feature in Gmail. New users can no longer set it up as of early 2026, and existing users will lose it later in the year. The suggested alternatives are either to configure automatic forwarding on the source account (which requires the source provider to support it and, as mentioned, does not work too reliably due to various anti-SPAM techniques) or to add the account in the Gmail mobile app – which helps exactly nobody who reads their e-mail on a desktop. Also it doesn’t give you the “search everything in one place” benefit.

So I needed a replacement. The idea was to connect to IMAP and use Gmails Import-API to get the mail into Gmail. So I wrote go-imapproc, a small Go daemon that connects to an IMAP mailbox and processes each unread message by piping it to an external program. When the program exits successfully, the message is marked as read (or deleted, or moved).

The “external program” in my case is a Python script bundled with the project (gws-import-to-gmail-direct.py) that takes the raw e-mail from stdin and imports it directly into Gmail via the Gmail REST API, using OAuth2 credentials managed by the Google Workspace CLI. This applies all the standard Google Spam filtering, which is quite good.

An additional upside: instead of polling on a timer, go-imapproc uses IMAP IDLE. The connection stays open and the server pushes a notification the moment a new message arrives. In practice, mail now shows up in my Gmail inbox within seconds of being delivered to my other inboxes – not within the next hour as it did due to Gmails 60 minute poll interval.

go-imapproc is open source and available on GitHub under the MIT license. The project includes the helper scripts for Gmail import, a built-in health endpoint, and a Docker setup if you prefer to run it containerized (as I always do).

Disclaimer: I used this project as an opportunity to gain more hands-on experience with AI-assisted development. The code-base is not “vibe coded” in the dismissive sense of the term, though. Significant effort went into unit and integration tests, following sound engineering principles, and making sure I actually understood and stood behind every piece of code that ended up in the repository. The AI was a tool, not a substitute for engineering judgment. All commits made by AI agents are clearly marked as such in the commit history.

The project has now been importing all my personal mails from several source-accounts for about 2-3 months now, all without any issues. I hope it will be usable to others as well.

P.S.: Importing to Gmail is just one use-case. There is a lot more you can script based on processing new incoming e-mails when they arrive.

Helper bash scripts to move projects from your small SSD to a larger HDD (and back)

I use a Dell 9020m Micro-PC as “terminal-server” for development. It has a small SSD, but also a larger HDD attached.

I’ve created two simple bash-scripts that help move projects I currently don’t work on from SSD to HDD. They add symlink to the “off-boarded” location so that I can basically keep on working on them, but with slower I/O. When I want to work on the project again (and need the I/O speed), the project is moved back to the SSD (“on-boarding”).

To make re-off-boarding fast, the on-boarded state is kept on the HDD and re-used when off-boarding the project again.

These two simple scripts have been released under MIT license on GitHub.

The power of git aliases

Based on a recent question on stackoverflow I found the power of git aliases and want so share one I invented for answering the question and after that I found very useful in everyday git use:

git config --global alias.add-commit '!git add -A && git commit'

After this, you can simply check in all new, modified, and deleted files with a simple

git add-commit -m 'My commit message'

I have aliased this command also to git ac in order to save further on typing. I never thought that this combination could be that useful, but actually I think it really is. Thanks to the questioner for bringing the idea up.

How to force Git to consider a file as binary

If you are using Git on Windows and follow my advise on how to get past the problem with the “suspicious patch lines”, you might run into problems if you are using Encapsulated PostScript (.eps) files in your repository.

PostScript files are almost plain-text files, and if you set core.autocrlf and core.safecrlf, they might cause problems with the EPS binary encoded parts, as they might be detected as text-files and therefore remove any CRLF and replace it with single LF, which can mess up the whole image.

To force Git to consider a file binary which it would consider as text-file otherwise, the easiest way is to add a .gitattributes file to the directory containing the file or to any parent directory. In my case, I normally add a .gitattributes file in the root of the repository, containing

*.eps -text -diff
*.jpg -text -diff
*.png -text -diff

In the file you set attributes to a path (or a pattern), or unset them (with the minus sign).  The text attribute is the attribute which tells that end-of-line normalization should be applied to a file. If you unset it, Git won’t mess with the line endings in the file and consider it binary.

More details can be found on the gitattributes man page.

My initial git settings for any repository

This is my cheat sheet for the settings I use for my git-repositories (list to be edited continuously):

Global settings:

git config –global user.name Martin Carpella
git config –global user.email xxx@yyy.invalid
git config –global color.ui auto

Per-repository settings:

git config core.autocrlf true
git config core.safecrlf true

Per-repository .gitignore for Visual Studio/C# projects:

bin
obj
*.user
*.suo
Thumbs.db

Test-driven network management

Article Teaser RJ45 close-upTest-driven development has proven to increase quality of software in many cases. I believe that the same principle should be applied to network management. From time to time, I am occupied in managing quite large and distributed networks, consisting of many different network segments, routers, servers, etc.

Primary tool in managing any network is using monitoring software which tells you if everything is alright or if you should worry. For various reasons I have become a huge fan of Nagios for monitoring networks I am responsible for, especially for the simple extensibility by writing your own check scripts (plugins).

While working through some issues in a network, I suddenly decided to try an approach I spontaneously called “test-driven network management”¹. The steps are easy (and are a one-to-one translation of agile software-development principles):

  1. Write a Nagios test which checks for the requested/required feature.
  2. This test will fail.
  3. Implement a solution satisfying the test.

The same advantages of automated testing (better: unit testing) in software development also apply to the network management tasks:

  • The test documents what you want to achieve in a quite formal way.
  • You will (almost) immediately know when your solution breaks other requirements (if tests exist for them).
  • As networks tend to be even more fragile then software, you have to monitor whatever you implemented anyways 🙂

Whenever possible, I try to add a test (or tweak an existing one) for any trouble-ticket / feature request I come around. In my experience, customer satisfaction tends to increase, because you start noticing problems before they do and you also implement measures to prevent the same problems to occur over and over again.

¹ I am quite sure there is another technical term for it, as I am quite sure I am not inventing anything new here… If you know how this is called by others, please tell me in the comments.

[tags]development, network, sysadmin, network management, test-driven development, nagios[/tags]

.NET strings are not always immutable!

Strings are immutable. If you want to modify a sequence of characters, use StringBuilder. At least, that’s whats officially said. But in the framework there is at least one method that does modify a string:

TextRenderer.MeasureText() with ModifyString and EndEllipses will modify your string to match the ellipsed text if ellipsing happens. You can look at this VB# example on codeproject using TextRenderer.MeasureText() for trimming text on how it is used.

The string seems to be modified directly in native code by DrawTextEx from user32.dll. Additionally to the scary fact that strings are not immutable, the length of the string is not updated, regardless if the resulting string is shorter!

For instance if you have a string “aaaaaaa” which will be truncated to “aa...“, the Length property will still return 7 for the shortened string. The debugger shows that the string will in fact be “aa…\0a” after the operation. So maybe it might be right that the string is still 7 characters long but most outputting functionality like Console.Out.WriteLine() gets confused sometimes and stops any further output to the debugger or console under certain conditions.

A very quick investigation of the System.Drawing assembly using Lutz Roeder’s fabulous .NET Reflector showed that at least there should be no memory corruption in case “WW” would get ellipsed to “W...“, as DrawTextEx takes the length of the buffer and should result only in “W.“.

Summing up, I find the corruption of an immutable string by an official Microsoft API very troubling.

Content-aware image resizing

Krispin made me aware of a very cool new technique for resizing images: content-aware image resizing. Based on an energy-function path of an image are removed when shrinking or are duplicated and interpolated when growing the image in a non-uniform way.

This technique can also be used to remove objects from a given image. There is a nice demo video available on YouTube (it’s the same as in jfo’s coding blog, where Krispin originally found the information):

[youtube vIFCV2spKtg]

(via jfo’s coding and slashdot)

Microsoft: Shared Source Common Language Infrastructure 2.0 Release

Just came accross this: seems like Microsoft has released some parts of the CLI under one of their “free” licenses.

Download details: Shared Source Common Language Infrastructure 2.0 Release

Update 2006/03/26: As I just noticed at Mono’s “Contributing” page, they won’t accept any contributions from people who had a look at the download.