Skip to content
0

NeoMutt mbsync

This guide outlines a robust workflow for moving old emails from a remote IMAP server to a local Maildir archive. This process helps free up space on your email server while ensuring you have a permanent, searchable local copy of your old mail.

The core principle is to maintain a local mirror of your remote mailbox using mbsync, perform the archival (moving files) on the local mirror, and then use mbsync again to propagate the local changes (the "deletions" from the mirrored folder) back to the remote server.

Prerequisites

  1. isync Installed: You must have isync (which provides the mbsync command) installed on your system.
  • mbsync/isync
  • notmuch
brew install isync

Create config file

  1. Configured isyncrc: A working ~/.config/isyncrc file must be set up for the target email account. The configuration must include Expunge Both to ensure that deletions on the local mirror are synced to the remote server.

两个任意选择一个就行:

  • ~/.mbsyncrc (older style but acceptable)
  • ~/.config/isyncrc I use this config file

Example isyncrc Channel configuration:

Channel twine
Far :twine-remote:
Near :twine-local:
Patterns *
Sync All
Expunge Both  # <-- This is critical for the workflow
Create Near
Remove Near
SyncState *

Making the directories

给你的每个邮箱帐户创建一个本地文件夹:

bash
~/.maildir/twine
~/.maildir/soundfreaq
~/.maildir/biaget

下面我们以 twine 为例进行配置。

The Archiving Process

Step 1: Perform a Full Initial Sync

Before making any changes, ensure your local mail mirror is perfectly up-to-date with the remote server. This is a critical safety step.

Run mbsync for your account (replace twine with your channel name if different):

bash
mbsync twine

Wait for this command to complete successfully. Your local ~/.maildir/twine/ directory now mirrors the remote server.

Step 2: Create the Local Archive Folder

Create a new directory on your local machine to store the archived emails. It's important to create it in the Maildir format, which requires cur, new, and tmp subdirectories.

bash
# Create an archive folder for emails from 2025
mkdir -p ~/.maildir/2025/{cur,new,tmp}

Step 3: Move Emails Locally with a Script

The safest way to move emails based on their date is to use a script. This script will find all emails in your local INBOX mirror on or before a specified date and move them to your archive folder.

  1. Create the script file:

    bash
    touch ~/move_old_emails.sh
    chmod +x ~/move_old_emails.sh
  2. Add the script content: Open ~/move_old_emails.sh in a text editor and paste the following code. Remember to adjust the configuration variables at the top if your setup is different.

    bash
    #!/bin/bash
    
    # --- Configuration ---
    # Your local synchronized INBOX folder (for the 'twine' account)
    SOURCE_INBOX="$HOME/.maildir/twine/INBOX"
    
    # Your local archive folder
    ARCHIVE_DIR="$HOME/.maildir/2025"
    
    # The cutoff date. Emails on or before this date will be moved.
    # Format: YYYY-MM-DD
    CUTOFF_DATE="2025-10-31"
    
    # --- Script Logic ---
    
    # Convert cutoff date to seconds since epoch for reliable comparison
    # For macOS/BSD date command:
    CUTOFF_SECONDS=$(date -j -f "%Y-%m-%d" "$CUTOFF_DATE" "+%s")
    
    echo "Archiving emails from $SOURCE_INBOX to $ARCHIVE_DIR"
    echo "Moving all emails dated on or before $CUTOFF_DATE"
    echo "---"
    
    # Ensure the archive's 'cur' directory exists
    mkdir -p "$ARCHIVE_DIR/cur"
    
    # Find all email files in the INBOX's 'cur' and 'new' subdirectories
    find "$SOURCE_INBOX/cur" "$SOURCE_INBOX/new" -type f | while read -r email_file; do
      # Extract the 'Date:' header from the email file
      date_header=$(grep -i -m 1 '^Date:' "$email_file")
    
      if [[ -n "$date_header" ]]; then
        # Clean up the date string (remove "Date: " prefix and timezone info in parentheses)
        email_date_str=$(echo "$date_header" | sed -E 's/^Date: //; s/\(.*\)//; s/\s+$//')
    
        # Convert the email's date to seconds since epoch
        # The '-j' flag is for BSD/macOS date; for GNU date, the syntax is different.
        email_seconds=$(date -j -f "%a, %d %b %Y %H:%M:%S %z" "$email_date_str" "+%s" 2>/dev/null)
    
        # If conversion fails, try another common format
        if [[ -z "$email_seconds" ]]; then
            email_seconds=$(date -j -f "%d %b %Y %H:%M:%S %z" "$email_date_str" "+%s" 2>/dev/null)
        fi
    
        # Compare the dates
        if [[ -n "$email_seconds" && "$email_seconds" -le "$CUTOFF_SECONDS" ]]; then
          echo "Moving: $(basename "$email_file")"
          mv "$email_file" "$ARCHIVE_DIR/cur/"
        fi
      fi
    done
    
    echo "---"
    echo "Local move complete."
  3. Execute the script:

    bash
    ~/move_old_emails.sh

The script will move all the targeted email files from ~/.maildir/twine/INBOX/ to ~/.maildir/2025/cur/.

Step 4: Propagate Deletions to the Remote Server

This is the final and irreversible step. Run mbsync again.

bash
mbsync twine

mbsync will detect that hundreds of files are missing from your local Near mirror (~/.maildir/twine/INBOX). Because of the Expunge Both setting, it will interpret this as a command to delete those same emails from the Far remote server.

Once the command finishes, the old emails are now gone from the server and reside safely in your local archive.

You can easily view your local archive in NeoMutt. You can either temporarily change your folder (c) to ~/.maildir/2025 or set up a separate account configuration in NeoMutt that points to your local maildirs for easy access.

Resources

最近更新