debiancompressionzlibdovecotmaildir

Dovecot compress existing maildir mails from postfix


I've taken code snippets from elsewhere and created a script to compress existing maildir emails (Dovecot would need to be stopped as I don't check for locks).

#!/bin/bash
store=/var/vmail/mydomain.com
find "$store" -type d -name "cur" | while read maildir; do

  tmpdir=$(cd "$maildir/../tmp" &>/dev/null && pwd) || exit 1

  find=$(find "$maildir" -type f -name "*,S=*" ! -name "*,*:2,*,*Z*" -printf "%f\n")
  if [ -z "$find" ]; then
    echo continue
    continue
  fi

  echo "$find" | while read filename; do

    if file "$maildir/$filename" | grep -q "SMTP mail, "; then

      echo 'Uncompressed' "$filename"

      flags=$(echo $filename | awk -F:2, '{print $2}')

      if echo $flags | grep ','; then
        newname=$filename"Z"
      else
        newname=$filename",Z"
      fi

      srcfile="$maildir/$filename"
      tmpfile="$tmpdir/$filename"
      dstfile="$maildir/$newname"

      gzip -c "$srcfile" > "$tmpfile" &&
      chown --reference="$srcfile" "$tmpfile" &&
      chmod --reference="$srcfile" "$tmpfile" &&
      touch --reference="$srcfile" "$tmpfile"

      if [ -f "$srcfile" ] && [ -f "$tmpfile" ]; then
        mv "$tmpfile" "$srcfile" &&
        mv "$srcfile" "$dstfile"
      else
        rm -f "$tmpfile"
      fi

    elif file "$maildir/$filename" | grep -q "gzip compressed data"; then
      echo 'Compressed' "$filename"
    else
      echo 'Unknown type'
    fi

  done
done

However I realised that my inbound mail doesn't get found, as not all of the emails meet the find criteria of -name "*,S=*"

Example

find "/var/vmail/mydomain.com" -type d -name "cur" | while read maildir; do find "$maildir" -type f -name "*,S=*" ! -name "*,*:2,*,*Z*" -printf "%f\n"; done

Will find these:

/var/vmail/mydomain.com/Maildir/.Sent/cur
1580000001.M10001P10008.ip-172-1-1-100,S=14037,W=14302:2,Sa
1580000002.M20002P10009.ip-172-1-1-100,S=3784,W=3888:2,S

However not these:

/var/vmail/mydomain.com/Maildir/.INBOX/cur
1580000003.Vca01I80f58M300003.ip-172-1-1-100:2,S
1580000004.Vca01I80de7M400004.ip-172-1-1-100:2,Sa
1580000005.Vca01I85252M400005.ip-172-1-1-100:2,RS
1580000006.Vca01I83ffeM400006.ip-172-1-1-100:2,Sb
1580000007.Vca01I8159aM400007.ip-172-1-1-100:2,RSa
1580000008.Vca01I84015M400008.ip-172-1-1-100:2,Sab

I could easily change the find command to match the inbound mail but as the find criteria came from elsewhere I wondered if there was a reason for the explicit "*,S=*"?

Ps. Please note that mail is not received through Dovecot, inbound mail is picked up by postfix which saves the mail directly to the relevant directory, postfix variables below for an example.

virtual_mailbox_base: /var/vmail
virtual_mailbox_maps: ldap lookup, %d/%u/Maildir/

Solution

  • You may consider searching for substring :2, in filenames.

    Dovecot: Maildir filename extensions

    The standard filename definition is: ":2,". […]
    * ,S=: contains the file size. Getting the size from the filename avoids doing a stat(), which may improve the performance. This is especially useful with Maildir++ quota.
    * ,W=: contains the file's RFC822.SIZE, ie. the file size with linefeeds being CR+LF characters. […]

    Uppercase letters mark "standard flags", lowercase letters mean "local/user flags".