cnoceda.com

Mail Workflow configuration

Hi everyone,
I've decided to write this quick post about the complete email workflow to clarify the process, which in Emacs can be complex and quite varied at times.

A preliminary diagram to show what we're going to talk about:

equema_correo.svg
Figure 1: Email diagram

Retrieving emails

I mainly use 3 email accounts:

Usage Provider
Work O365
Personal fastmail
Personal gmail

O365

This setup is the most complicated one, because Microsoft and companies don't make it easy. The most complex part is authentication, in my case two-factor authentication.
The most important thing is to understand what limitations your company imposes on mail access.
In my case, they currently allow connection via HTTPS through EWS. To synchronize, I use software that supports two-factor authentication and acts as a bridge between EWS and IMAP. This application is davmail. You can download it from Download davmail.
mbsync connects to Davmail via IMAP to fetch the emails.

Fastmail and Gmail

These accounts are synced directly with mbsync, which connects to Gmail's IMAP, and to fastmail.com via an app-specific password. You can check Fastmail's info here: Server name and ports. They have a page with lots of configuration details.

mbsync configuration

My work mailbox is about 4GB in size. It has folders where I manually archive email, and a group of folders with automatic archiving that I don’t want to sync. Full sync takes a while, so I’ve developed a different strategy:

This allows me to stay updated with high-traffic folders, and review the others less frequently.

Here’s how I configure it:

IMAPAccount company
Host 127.0.0.1
Port 1143
Timeout 300
SSLType none
AuthMechs LOGIN
User "user@es.company.com"
CertificateFile /etc/ssl/certs/ca-certificates.crt
PassCmd "PASSWORD_STORE_DIR=/home/user/password-store pass es.company.com/user"
PipelineDepth 1

IMAPStore company-remote
Account company

MaildirStore company-local
Path ~/maildir/company.com/
Inbox ~/maildir/company.com/inbox
SubFolders Verbatim

Channel company-inbox
Far :company-remote:
Near :company-local:
Patterns  "INBOX"
Create Both
Expunge Both
CopyArrivalDate yes
SyncState *

Channel company-projects
Far :company-remote:
Near :company-local:
Patterns  "INBOX/1_PROJECTS/*"
Create Both
Expunge Both
CopyArrivalDate yes
SyncState *

Channel company-areas
Far :company-remote:
Near :company-local:
Patterns  "INBOX/2_AREAS/*"
Create Both
Expunge Both
CopyArrivalDate yes
SyncState *

Channel company-resources
Far :company-remote:
Near :company-local:
Patterns "INBOX/3_RESOURCES/*"
Create Both
Expunge Both
CopyArrivalDate yes
SyncState *


Channel company-archives
Far :company-remote:
Near :company-local:
Patterns  "INBOX/4_ARCHIVES/*"
Create Both
Expunge Both
CopyArrivalDate yes
SyncState *

Channel company-sent
Far :company-remote:Sent
Near ":company-local:Elementos\ enviados"
Create Both
Expunge Both
CopyArrivalDate yes
SyncState *

Channel company-trash
Far :company-remote:Trash
Near ":company-local:Elementos\ eliminados"
Create Both
Expunge Both
CopyArrivalDate yes
SyncState *

Channel company-drafts
Far :company-remote:Drafts
Near :company-local:Borradores
Create Both
Expunge Both
CopyArrivalDate yes
SyncState *

Channel company-unsent
Far ":company-remote:Unsent Messages"
Near ":company-local:Bandeja\ de\ salida"
Create Both
Expunge Both
CopyArrivalDate yes
SyncState *

# Group of folders that sync every 10 min.
Group company
Channel company-inbox
Channel company-sent
Channel company-trash
Channel company-drafts
Channel company-unsent

# Group of folder that sync every hour
Group company-other
Channel company-projects
Channel company-areas
Channel company-resources
Channel company-archives

# =============================
# All folders sync at the same time
IMAPAccount gmail
Host imap.gmail.com
User "user@gmail.com"
Port 993
SSLType IMAPS
AuthMechs LOGIN
PassCmd "PASSWORD_STORE_DIR=/home/user/password-store pass gmail.com/user"

IMAPStore gmail-remote
Account gmail

MaildirStore gmail-local
SubFolders Verbatim
Path ~/maildir/gmail.com/
Inbox ~/maildir/gmail.com/inbox

Channel gmail
Far :gmail-remote:
Near :gmail-local:
Patterns * !"[Gmail]/All Mail" !"[Gmail]/Important" !"[Gmail]/Starred" !"[Gmail]/Spam" !"Notes"
Create Near
Sync All
Expunge Both
SyncState *

# ==============================
# All folders sync at the same time
IMAPAccount fastmail
Host imap.fastmail.com
User "user@fastmail.com"
Pass "XXXXXXXXXXXXX"
Port 993
SSLType IMAPS
AuthMechs LOGIN

IMAPStore fastmail-remote
Account fastmail

MaildirStore fastmail-local
SubFolders Verbatim
Path ~/maildir/fastmail.com/
Inbox ~/maildir/fastmail.com/inbox

Channel fastmail-inbox
Far :fastmail-remote:
Near :fastmail-local:
Patterns "INBOX" "Notes" "Memos"
CopyArrivalDate yes
Create Both
Expunge Both
SyncState *

Channel fastmail-others
Far :fastmail-remote:
Near :fastmail-local:
Patterns  "INBOX/*" "Notes/*" "Memos/*"
Create Both
Expunge Both
CopyArrivalDate yes
SyncState *

Group fastmail
Channel fastmail-others
Channel fastmail-inbox

Synchronization and tagging

To run the tagging and sync workflow, I use crontab. I have a script called mail_sync scheduled every 10 minutes, which does all the work.

Here’s a diagram of how it works, and you can find the scripts in configuration files.

mail_sync.svg
Figure 2: Mail Sync

About tagging

All mail configuration is stored in an org-mode file where I keep the script code. This file also includes some tables that get converted into notmuch commands to manage spam or move emails.
A table like this:

noreply@medium.com
info@ofertasprive.com
@creativemarket.com

Generates, using the following code, a script with instructions to mark spam for deletion.

(let((command "notmuch tag +archived +trashed -inbox  -unread -- tag:gmail AND not tag:trashed AND"))
  (concat command (mapconcat (lambda (en) (format " from:%s" (car en))) emails)))

These are the lines inside the tag-rules script:

# *******************************************
#    Elisp generated code
# *******************************************

# *******************************************
#    End elisp generated code
# *******************************************

About moving emails

All mail is stored in the maildir folder, with a subfolder for each account: company.com, gmail.com, fastmail.com. These are synced with mbsync.

I also have 3 other folders outside of sync to archive emails for each account: archive_company.com, archive_gmail.com, archive_fastmail.com. This frees up the online inboxes.
The reason for the naming is that it helps with moving emails, since I maintain the original folder structure.

The scripts that move the mail files are a bit special. The move isn't just for archived emails. In my work account, I need to move them to folders within the mailbox, and to do this correctly, the file name has to be modified. If not, mbsync gets confused. The format is as follows:

1764049809.5009_3.void-slimx,U=70145:2,

This maildir format is what mbsync uses. If you want to move a message, you must remove the U=70145 from the new name.
This is what the safe-move and safe-move-arch scripts do. They could probably be unified, but I’ve kept them separate since the beginning and haven’t revisited them.

I think the most important things are documented here, but if I’ve missed anything or you need more info, you know where to find me. I've a bunch of elisp functions in the notmuch configuration to manage the tagging in Emacs, if you're interested let me know.

Author: Unknown

Date: 2025-11-24

Emacs 30.2 (Org mode 9.7.11)