#!/usr/bin/env bash # fix-mail-duplicates.sh # Usage: fix-mail-duplicates.sh /path/to/maildir 682 set -e # Check if arguments were provided if [ $# -ne 2 ]; then echo "Usage: $0 /path/to/maildir UID_NUMBER" echo "Example: $0 ~/Mail/ben@bensima.com/Archive 682" exit 1 fi MAILDIR="$1" UID_NUM="$2" # Validate the arguments if [ ! -d "$MAILDIR" ]; then echo "Error: Maildir '$MAILDIR' does not exist or is not a directory" exit 1 fi if ! [[ "$UID_NUM" =~ ^[0-9]+$ ]]; then echo "Error: UID must be a number, got '$UID_NUM'" exit 1 fi echo "Looking for duplicate UID $UID_NUM in $MAILDIR..." # Find all files with the EXACT UID (using word boundaries) DUPLICATE_FILES=$(find "$MAILDIR" -type f -name "*,U=$UID_NUM[,:]*") FILE_COUNT=$(echo "$DUPLICATE_FILES" | wc -l) if [ "$FILE_COUNT" -le 1 ]; then echo "No duplicates found. Nothing to fix." exit 0 fi echo "Found $FILE_COUNT files with the same UID $UID_NUM" # Get timestamps for each file to determine which is newer declare -A FILE_TIMES for f in $DUPLICATE_FILES; do # Get the message Date: header if possible, otherwise use file time if command -v formail >/dev/null 2>&1; then DATE_HDR=$(formail -xDate: < "$f" 2>/dev/null) if [ -n "$DATE_HDR" ]; then # Convert to epoch seconds if possible MSG_TIME=$(date -d "$DATE_HDR" +%s 2>/dev/null) if [ $? -eq 0 ]; then FILE_TIMES["$f"]="$MSG_TIME" continue fi fi fi # Fallback to file modification time FILE_TIMES["$f"]=$(stat -c %Y "$f") done # Find the oldest file (we'll keep its UID) OLDEST_FILE="" OLDEST_TIME=9999999999 for f in "${!FILE_TIMES[@]}"; do if [ "${FILE_TIMES[$f]}" -lt "$OLDEST_TIME" ]; then OLDEST_TIME="${FILE_TIMES[$f]}" OLDEST_FILE="$f" fi done echo "Keeping original UID on oldest file: $OLDEST_FILE" # Rename all newer files by removing the UID part for f in $DUPLICATE_FILES; do if [ "$f" != "$OLDEST_FILE" ]; then # More precise sed pattern to avoid partial UID matches NEW_NAME=$(echo "$f" | sed "s/,U=$UID_NUM\([,:]\)/, \1/" | sed "s/:2,/,/") echo "Renaming newer duplicate:" echo " From: $f" echo " To: $NEW_NAME" mv "$f" "$NEW_NAME" fi done echo "Fixed UID collision for UID $UID_NUM. Please run mbsync again."