For the past five years, kaleshian.net had SMTP and IMAP hosted through AWS WorkMail. It worked well for me as an individual but I realized that the user experience, especially through the portal left a lot to be desired. In addition,I had to consider that the family domain was going to host more than one active user in the very near future (given that the boys are needing access to e-mail). In this post, I describe the windy path of migrating from WorkMail to Workspace.

As a daily Linux user, I spend as much time as I can interacting with communities, services, and systems through a terminal window. The only graphical UI that I use is a browser because Links has a tough time rendering images1. My daily setup for interacting with e-mail is through a combination of OfflineIMAP, NeoMutt, [msmtp][5, and notmuch. By orchestrating the configuration of these tools, I’m able to effectively manage e-mail through a single interface, completely through the keyboard in a terminal window. The challenge of using WorkMail was that while it satisfied my requirement (as I rarely interacted with e-mail through their UI), my family members dreaded the experience (in comparison to the other large e-mail providers). This led me to find a solution that would satisfy my requirement along with their’s.

Well, Armen, why didn’t you just use O365 as a replacement? Because Microsoft is deprecating personalized e-mail addresses by November 30, 2023.

It was actually my first choice and I was really disappointed when I read the announcement. I considered standing up an Azure Active Directory instance, and building out O365 against it but decided that it would be complete overkill for the family’s needs. I wanted to keep the management overhead as low as possible. In addition, if I ever wanted to apply family controls to the boys’ Microsoft accounts, I wouldn’t be able to as you cannot associate an e-mail created through AAD to a personal Microsoft account. At this point, setting up a Google Workspace was my last option.

Once the decision was made, setting up the Workspace was straight forward and updating the domain MX records were seamless. The concern I had was how to migrate 6K e-mails from one service to another by using my existing toolset. The alternatives were to use Google’s Data Migration Service or keep the WorkMail account live for a period of time while Google imported e-mail over time via… POP3.

Enter OfflineIMAP.

By design, OfflineIMAP adheres to the IMAP standard which is enabled by default for both WorkMail and Workspace. My assumption would be that I could sync the contents of my WorkMail account locally one last time with OfflineIMAP after MX was updated and then use it again after a small configuration change to push the contents to my Workspace account. Without any customization, OfflineIMAP creates a Maildir structure for each account that’s configured during a synchronization using the exact name of the folders in the service. This presents a bit of an issue when your intent is to migrate contents from one directory structure to another.

When I first adopted my e-mail toolset, I spent a considerable time leveraging the nametrans and folderfilter options of OfflineIMAP to bring consistency when interacting with my e-mail (especially across accounts).

[Repository kaleshian@local]
nametrans = lambda folder:  re.sub('archive', '[Gmail]/All Mail',
	re.sub('drafts', '[Gmail]/Drafts',
	re.sub('flagged', '[Gmail]/Starred',
	re.sub('trash', '[Gmail]/Trash',
	re.sub('spam', '[Gmail]/Spam',
	re.sub('inbox', 'INBOX', folder))))))

[Repository kaleshian@remote]
nametrans = lambda folder:  re.sub('\[Gmail\]\/All Mail', 'archive',
	re.sub('\[Gmail\]\/Drafts', 'drafts',
	re.sub('\[Gmail\]\/Starred', 'flagged',
	re.sub('\[Gmail\]\/Trash', 'trash',
	re.sub('\[Gmail\]\/Spam', 'spam',
	re.sub('INBOX', 'inbox', folder))))))

folderfilter = lambda folder: folder in ['[Gmail]/All Mail',
	'[Gmail]/Drafts',
	'[Gmail]/Starred',
	'[Gmail]/Trash',
	'[Gmail]/Spam',
	'INBOX']

There are two blocks above for the account definition in my OfflineIMAP configuration. The first is for the local definition, and the second is for how the service will interact with the IMAP directory structure remotely.

In this case, the local nametrans (or name transformation) is exactly as defined in the remote block, except that it’s reversed. The intent of each definition is to take the remote server structure, and convert it to a user defined standard locally. For my case, I wanted the standard e-mail containers (e.g., inbox, drafts, flagged, trash, and spam) to all the look the same regardless of what account I was reviewing mail in.

The remote for WorkMail had a very different structure, but because I had ensured that locally, all of the accounts had matching directory structures, I was able to point the localfolder for the new remote target to the same directory structure, and let OfflineIMAP sync the contents to the Workspace account.

Overall, I was really pleased with the process and how well OfflineIMAP continues to work for my needs.

  1. This was a joke.