Skip to content

Instantly share code, notes, and snippets.

@colinmollenhour
Created November 21, 2012 21:10
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save colinmollenhour/4127743 to your computer and use it in GitHub Desktop.
Save colinmollenhour/4127743 to your computer and use it in GitHub Desktop.
IMAP Learn
#!/bin/bash
#
# IMAP Learn
#
# Copyright 2012 Colin Mollenhour (http://colin.mollenhour.com)
#
###############################################################################
#
# This script allows you to use an imap account to train your spamassassin server.
# Example script:
#
# #!/bin/bash
# AUTH="--server imap.example.com:993 --user user@example.com --password SECRET"
# SA_ARGS="--dbpath /etc/spamassassin/.spamassassin"
# imap_learn.sh $AUTH --folder "Junk E-mail" --type spam --delete-remote -- $SA_ARGS
# imap_learn.sh $AUTH --folder "Ham" --type ham -- $SA_ARGS
# sa-learn $SA_ARGS --sync
#
# Notes:
# - SSL support is required, port must be specified in --server option
# - Spamassassin already tracks duplicates so duplicate learning is not a concern
# - After running imap_learn, you should run "sa-learn --sync"
#
###############################################################################
LEARN=1
KEEP_LOCAL=0
KEEP_REMOTE=1
SINCE=$(date +%d-%b-%Y -d '-3 days')
SLEEP_TIME=1
while true; do
[ -n "$1" ] || break
arg="$1"; shift
case "$arg" in
--server)
IMAP_SERVER="$1"
;;
--user)
IMAP_USER="$1"
;;
--password)
IMAP_PW="$1"
;;
--folder)
IMAP_FOLDER="$1"
;;
--since)
SINCE="$1"
;;
--type)
TYPE="$1"
;;
--dry-run)
LEARN=0
continue
;;
--keep-local)
KEEP_LOCAL=1
continue
;;
--delete-remote)
KEEP_REMOTE=0
continue
;;
--)
break
;;
*)
echo "Invlaid argument: $arg"
exit 1
;;
esac
shift
done
if [ -z "$IMAP_SERVER" -o -z "$IMAP_USER" -o -z "$IMAP_PW" -o -z "$IMAP_FOLDER" -o -z "$SINCE" -o -z "$TYPE" ]; then
echo "You did not specify all required arguments."
exit 1
fi
connect_imap="openssl s_client -crlf -connect $IMAP_SERVER"
pause="sleep $SLEEP_TIME"
IDS="$(
$connect_imap < <(
echo "A01 LOGIN $IMAP_USER $IMAP_PW";
$pause; echo "A02 SELECT \"$IMAP_FOLDER\"";
$pause; echo "A03 SEARCH SEEN SINCE $SINCE";
$pause; echo "A04 LOGOUT";
$pause; echo "";
) 2>/dev/null | tr -d "\r" | grep -E "^[*] SEARCH" | sed "s/^[*] SEARCH \([0-9 ]*\)$/\1/g";
)";
if [ "$IDS" = "" ]; then
echo "No messages for $IMAP_USER"
exit
fi
tmpfile=$(mktemp /tmp/$TYPE.XXXX)
$connect_imap < <(
echo "A01 LOGIN $IMAP_USER $IMAP_PW";
$pause; echo "A02 SELECT \"$IMAP_FOLDER\"";
for id in $IDS; do $pause; echo "A03 FETCH $id BODY[]"; done
$pause; echo "A04 LOGOUT";
) 2>/dev/null > $tmpfile
if [ $KEEP_REMOTE -eq 0 ]; then
$connect_imap < <(
echo "A01 LOGIN $IMAP_USER $IMAP_PW";
$pause; echo "A02 SELECT \"$IMAP_FOLDER\"";
$pause; echo "A03 STORE ${IDS// /,} +FLAGS (\Deleted)";
$pause; echo "A04 EXPUNGE";
$pause; echo "A05 LOGOUT";
) 2>&1 > /dev/null
fi
echo Fetched Messages: ${IDS// /,} into $tmpfile
tmpdir=$tmpfile-emails/
mkdir -p $tmpdir || { echo Could not make $tmpdir; exit 1; }
awk "
BEGIN { p=0; i=0; }
/^\\)\\r$/ { p=0; }
{ if (p) print \$0 >> \"$tmpdir\"i\".eml\"; }
/[*] [0-9]+ FETCH/ { if (!p) { p=1; i++; } }
END { print \"Found \"i\" emails\"; }
" $tmpfile
[ $LEARN -eq 1 ] && sa-learn --$TYPE --no-sync "$@" $tmpdir
[ $KEEP_LOCAL -eq 1 ] || rm -rf $tmpfile $tmpdir
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment