One of the projects that I am involved in has a requirement of importing all the historical emails from a number of Gmail accounts into another system. It’s not the most challenging of tasks, but since I spent a bit of time on it, I figured I should blog it here too, just in case a similar need will arise in the future.
In my particular case, I need two different solutions. One for exporting all of the messages from all folders of all Gmail accounts in question (Gmail for Work). And the other is for exporting only the messages from the “Sent Mail” folder, which were sent on specific dates.
The solution that I derived is based on the classic tools for this purpose – fetchmail and procmail. Fetchmail is awesome at fetching emails using all kinds of protocols. Procmail is amazing at sorting, filtering, and otherwise processing the email messages.
So, here we go. First of all, we need to tell fetchmail where to get the messages from. I didn’t want to create to separate configurations for each of my tasks, so I left only the options common between them in the configuration file, and the rest I will be passing as command line arguments, depending on scenario.
Note that I’ve been running these tests from a dedicated environment, where I only had the root user. You don’t have to run it as root – it’ll work as any other just fine. Also, keep in mind that I used “/root/fetchmail-test/” folder for my test runs. You might need to adjust the paths if you have it any different.
Here’s my fetchmail.rc file, which I used to test a single mailbox. A new “poll” section will go into this file later, for each mailbox that I’ll need to export.
poll imap.gmail.com proto imap:
username "email@example.com" is root here
If you are not root, you might need to adjust the second line, replacing “root” with your username. Also, for testing purposes, you can use “fetchlimit 1” instead of “fetchall“.
Now, we need two configuration files for procmail. The first one is super simple – I’ll use this for simply pushing all downloaded messages into a single giant mbox file. Here’s the procmail-all.rc:
As you can see, it only defines the verbosity level and the default mailbox. The second configuration file is a bit more complicated. I’ll use it for the sent items only. The sent items folder limit will be done with fetchmail. But I want to do further is disregard all messages, which were not sent on a specific date. Here is my procmail-sent.rc:
* ^Date: .*28 Jul 2016.*|\
^Date: .*27 Jul 2016.*
Again, we have the verbosity level and the default mailbox to save messages to. Since I want to disregard them unless they match a certain condition, I specify /dev/null. Then, I specify my condition, which is simply a bunch of regular expressions for the Date header. Usually, Date header is a not very reliable as different MUAs (Mail User Agents) use different formats, time zones, etc. In this particular case test results seemed consistent (maybe Gmail fixes the header), and I didn’t have any other more reliable criteria to use.
As you can see, I use a very basic condition for date matching. So, if the Date header matches either “28 Jul 2016” or “27 Jul 2016“, the message is saved in the mbox file, rather than being thrown into the default mailbox.
Now, all I need is a way to tie fetchmail and procmail together, as well as provide some additional options. For that I created the two one-liner shell scripts, just so that I won’t need to figure out the command line arguments if I look at this whole thing six month later.
Here is the check-all.sh script (multi-line for readability):
fetchmail -f fetchmail.rc \
-r "[Gmail]/All Mail" \
--mda "procmail /root/fetchmail-test/procmail-all.rc"
and here is the check-sent.sh script (multi-line for readability):
fetchmail -f fetchmail.rc \
-r "[Gmail]/Sent Mail" \
--mda "procmail /root/fetchmail-test/procmail-sent.rc"
If you run either one of these scripts, you’ll see the output similar to this:
fetchmail: WARNING: Running as root is discouraged.
410 messages for firstname.lastname@example.org imap.gmail.com (folder [Gmail]/All Mail).
reading message email@example.com@gmail-imap.l.google.com:1 of 410 (446 header octets) (222 body octets) not flushed
reading message firstname.lastname@example.org@gmail-imap.l.google.com:2 of 410 (869 header octets) (230 body octets) not flushed
reading message email@example.com@gmail-imap.l.google.com:3 of 410 (865 header octets) (230 body octets) not flushed
Here are a few resources that you might find helpful: