[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[msmtp-users] [denis.golovan@...20...: msmtp queue script]
Hi, all!
If somebody uses msmtpq script for queue management. Please give feedback on my patch.
Thanks.
----- Forwarded message from Denis Golovan <denis.golovan@...20...> -----
From: Denis Golovan <denis.golovan@...20...>
Subject: msmtp queue script
To: marlam@...23...
Date: Tue, 26 Feb 2008 15:40:49 +0200
User-Agent: Mutt/1.5.16 (2007-06-09)
Message-ID: <20080226134049.GY8748@...134...>
Hi, Martin.
I've read your post in msmtp mailing list on queue script.
I found your work useful, thanks.
But, I found some bugs.
Here is patched version of send_mail function (I am not bash guru :) ).
** quotes mean my comments. Patch is also in attach.
Using previous version of send_mail function lead to enqueueing successfully sent messages in mail folder. All *.mail files were empty though (cat
patch part).
Also I don't quite understand & in msmtp invocation - it seems to me, that result code could be wrong??
My app versions:
GNU bash, version 3.2.17(1)-release (i686-pc-linux-gnu)
msmtp version 1.4.7
Some feature request, if you please :)
1. Form some kind of options area with constants. Such as google ip, log file and etc
2. Write dsp function output to log
3. Insert script version :). BTW what is the current (msmtp mailing list 2008-01-27) version number?
If you are not against, I'd like to make those feature request changes myself and send you for "publishing".
Best regards,
Denis Golovan
--- msmtpq 2008-02-26 15:28:03.000000000 +0200
+++ msmtpq.1 2008-02-26 15:32:28.000000000 +0200
@@ -25,9 +25,10 @@
#--------------------------------------------------------------
#Q=$HOME/.msmtp.queue # the queue
-Q=~/.msmtp.queue # the queue
+Q=~/mail/mqueue # the queue
umask 077 # set secure permissions on created directories and files
declare -i CNT # a count of mail(s) in the queue
+declare TFILE
usage() {
echo
@@ -86,7 +87,7 @@
for M ; do
if [ -n "$M" ] ; then
- echo " $M"
+ echo " $M" >> ~/mail/logs/msmtpq.log
else
echo
fi
@@ -100,9 +101,11 @@
local -i RC # msmtp return code
if /bin/ping -qnc 1 -w 2 64.233.183.147 &> /dev/null ; then # ip addr of www.google.com
- /bin/cat | /usr/bin/msmtp "$@" > /dev/null & # send mail immediately
+ #/bin/cat | /usr/bin/msmtp "$@" > /dev/null & # **seems pretty strange - return without waiting for result** send mail immediately
+ /bin/cat "$TFILE" | /usr/bin/msmtp "$@" > /dev/null # send mail immediately
RC=$?
- if $RC ; then # send was successful
+ #if $RC; then #**by some reason 0 result leads to "mail send was unsuccessful"**
+ if [ $RC = 0 ]; then # send was successful, **works as expected**
dsp 'mail sent'
else
dsp 'mail send was unsuccessful' \
@@ -130,7 +133,7 @@
echo "$@" > "${BASE}.msmtp" || dsp -e 'writing msmtp cmd line' \
"to ${BASE}.msmtp failed" # write command line to .msmtp file
- /bin/cat > "${BASE}.mail" || dsp -e 'writing mail' \
+ /bin/cat "$TFILE" > "${BASE}.mail" || dsp -e 'writing mail' \
"to ${BASE}.mail failed" # write mail to .mail file
dsp 'mail queued'
}
@@ -252,10 +255,22 @@
done
}
+cleanup()
+{
+ #remove temporary message file
+ rm -f $TFILE
+}
+
#
## -- entry point
#
+trap cleanup 0 1 2 3 6 9 14 15
+#message from standart input
+#because /bin/cat does not repeat its output on subsequent runs :)
+TFILE="/tmp/$(basename $0).$$.tmp"
+/bin/cat > $TFILE
+
# check what we're being called as - 'msmtpq' or 'msmtpQ'
if [ "$(/usr/bin/basename $0)" == 'msmtpQ' ] ; then # called as msmtpQ
if [ -n "$1" ] ; then # if arg(s)
#!/bin/sh
#--------------------------------------------------------------
#
# msmtpq : queue funtions to use and manage the msmtp queue,
# as it was defined by Martin Lambers
# Copyright (C) 2008 Chris Gianniotis
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or (at
# your option) any later version.
#
#--------------------------------------------------------------
#--------------------------------------------------------------
# the msmtp queue contains unique filenames of the following form :
# two for each mail in the queue
#
# create new unique filenames of the form :
# MLF: ccyy-mm-dd-hh.mm.ss[-x].mail -- mail file
# MSF: ccyy-mm-dd-hh.mm.ss[-x].msmtp -- msmtp command line file
# where x is a consecutive number only appended for uniqueness
# if you send more than one mail per second
#--------------------------------------------------------------
#Q=$HOME/.msmtp.queue # the queue
Q=~/mail/mqueue # the queue
umask 077 # set secure permissions on created directories and files
declare -i CNT # a count of mail(s) in the queue
declare TFILE
usage() {
echo
echo ' usage : msmtpq functions'
echo
echo ' msmtpq <op> --'
echo ' ops : -s send a mail'
echo ' -sr send a mail, then run queue'
echo ' -e enqueue a mail'
echo ' -er enqueue a mail, then run queue'
echo
echo ' -r run (flush) mail queue'
echo ' -d display (list) queue'
echo ' -m purge a single mail from queue'
echo ' -a purge all mail in queue'
echo ' -h this helpful blurt'
echo
echo ' -s an outgoing mail will normally be sent directly out,'
echo ' if connected, otherwise it is queued'
echo ' -e causes the mail to be enqueued'
echo ' -r flushes the mail queue, if anything is there'
echo ' -sr if connected sends out the mail then flushes the queue'
echo ' otherwise enqueues it'
echo ' -er enqueues the mail then flushes the queue'
echo ' (but why would anyone want to do this ?)'
echo
echo ' - note that only one op per invocation is allowed'
echo ' - the only combined ops are the ones listed above'
echo ' - if more than one op is specified, the first one'
echo ' only is executed'
echo ' - for -s, -e, -sr or -er the msmtpq op MUST be followed'
echo " by '--' to separate it from any msmtp options"
echo
}
# verify that msmtp queue is present
# the first version can be used if you'd like to create the queue dir
# if it's not found ; I'd rather just be warned if it's not there
check_queue() { # make certain queue dir is present
#if [ ! -d "$Q" ] ; then # queue dir present or
# /bin/mkdir -p "$Q" || dsp -e 'could not create queue dir'
#fi # create it
if [ ! -d "$Q" ] ; then # queue dir not present
dsp -e " can't find $Q" # complain
fi
}
# display a message, possibly an error
dsp() {
local M ERR
if [ "$1" == '-e' ] ; then
ERR='t'
shift
fi
for M ; do
if [ -n "$M" ] ; then
echo " $M" >> ~/mail/logs/msmtpq.log
else
echo
fi
done
[ -n "$ERR" ] && exit 1
}
# send a mail (otherwise queue it)
send_mail() { # <-- all mail args # send or enqueue a mail
local -i RC # msmtp return code
if /bin/ping -qnc 1 -w 2 64.233.183.147 &> /dev/null ; then # ip addr of www.google.com
#/bin/cat | /usr/bin/msmtp "$@" > /dev/null & # **seems pretty strange - return without waiting for result** send mail immediately
/bin/cat "$TFILE" | /usr/bin/msmtp "$@" > /dev/null # send mail immediately
RC=$?
#if $RC; then #**by some reason 0 result leads to "mail send was unsuccessful"**
if [ $RC = 0 ]; then # send was successful, **works as expected**
dsp 'mail sent'
else
dsp 'mail send was unsuccessful' \
dsp "msmtp rc = $RC ; enqueuing mail"
enqueue_mail "$@"
fi
else # not connected
enqueue_mail "$@" # enqueue mail
fi
}
# enqueue a mail
enqueue_mail() { # <-- all mail args # enqueue a mail
local BASE # base name
local -i INC # increment counter for basename collision
BASE="$Q/`/bin/date +%Y-%m-%d-%H.%M.%S`" # make unique base filename
if [ -f "$BASE.*" ] ; then # base filename exists
INC=1 # initial increment to 1
while [ -f "${BASE}-${INC}.*" ] ; do
INC="(( ++INC ))" # filename exists ; bump increment
done
BASE="${BASE}-${INC}" # unique ; set base filename
fi
echo "$@" > "${BASE}.msmtp" || dsp -e 'writing msmtp cmd line' \
"to ${BASE}.msmtp failed" # write command line to .msmtp file
/bin/cat "$TFILE" > "${BASE}.mail" || dsp -e 'writing mail' \
"to ${BASE}.mail failed" # write mail to .mail file
dsp 'mail queued'
}
# run (flush) queue
run_queue() { # run queue
local LOC="$Q/.lock" MLF MSF # lock file name ; queued mail filename pairs
local -i MAX=120 SEC=0 RC # max seconds to gain a lock ; seconds waiting
if (( $(/bin/ls -1 *.mail 2> /dev/null | /usr/bin/wc -l) > 0 )) ; then # if any mail in Q
# attempt to lock queue
while [ -e "$LOC" ] && (( SEC < MAX )) ; do # if a lock file there
/bin/sleep 1 # wait a second
(( ++SEC )) # accumulate seconds
done # try again while locked for MAX secs
if [ -e "$LOC" ] ; then # lock file still there, give up
dsp -e '' "cannot use $Q : waited $MAX seconds for" \
" lockfile $LOC to vanish, giving up" \
'if you are sure that no other instance of this script' \
' is running, then delete the lock file' ''
fi
/bin/touch "$LOC" || exit 1 # lock queue
for MLF in *.mail ; do # process all mails
dsp "sending $MLF ..." # scratch user's itch
MSF="${MLF%.*}.msmtp"
if [ ! -f "$MSF" ] ; then # no corresponding MSF file found
dsp "corresponding file $MSF not found" \
'check this ...' # give user the bad news
continue # crank on
fi
/usr/bin/msmtp $(/bin/cat "$MSF") < "$MLF" # the mail goes out the door
RC=$?
if $RC ; then # send was successful
/bin/rm "$MLF" "$MSF" # nuke the files
dsp "$MLF sent successfully" # good news to user
else # send unsuccessful
dsp "$MLF send failed" \
"msmtp rc = $RC" \
'check this out ...' # bad news ...
fi
done
else # no mails in queue
dsp '' 'mail queue is empty' '' # inform user
fi
/bin/rm -f "$LOC" # remove the lock
}
# display queue
display_queue() {
local LST M # list of mails in queue ; each mail
echo
LST="$(/bin/ls $Q/*.mail 2>/dev/null)"
(( CNT = 0 ))
if [ -n "$LST" ] ; then
for M in $LST ; do
echo " mail id = [$(/usr/bin/basename $M .mail)]" # show mail id
/bin/egrep -s --colour -h '(^From:|^To:|^Subject:)' "$M" # show mail info
(( CNT++ ))
echo
done
else
dsp 'no mail in queue' ''
fi
}
# delete all mail in queue
purge_all_mail() { # <-- question txt, positive ack txt
local YN I C # confirmation response ; question text ; ack text
if [ "$1" == '-1' ] ; then # queue contains single mail
I="remove the only mail from the queue"
C="single mail purged from queue"
else # queue contains multiple mails
I="remove (purge) all mail from the queue"
C="msmtp queue purged"
display_queue
fi
echo -n " $I [y/N] ? ...: " ; read YN
case $YN in
y|Y) /bin/rm -f "$Q"/*.* # msmtp - nukes all mail in queue (dir)
dsp '' "$C ..." ''
;;
*) dsp '' 'nothing done ; queue is untouched ...' ''
;;
esac
}
purge_a_mail() {
local ID # id of mail being deleted
while true ; do # purge an individual mail from queue
display_queue # show queue contents, if any
if (( CNT > 0 )) ; then # something there
if (( CNT == 1 )) ; then # only one mail
purge_all_mail -1 # purge it
else # more than one mail
echo ' remove (purge) a mail from the queue ; enter its id'
echo -n ' ( <cr> to exit ) ...: ' ; read ID
if [ -n "$ID" ] ; then # <-- file name (only, no suff)
if [ -n "$(/bin/ls "$Q"/"$ID".* 2>/dev/null)" ] ; then
/bin/rm "$Q"/"$ID".* # msmtp - nukes a single mail in queue (dir)
dsp '' "mail [$ID] purged ..."
else # invalid id entered
dsp '' "mail [$ID] not found ; bad id ..."
fi
else # nothing entered
dsp '' 'nothing done ; queue is untouched ...' ''
break
fi
fi
else
break
fi
done
}
cleanup()
{
#remove temporary message file
rm -f $TFILE
}
#
## -- entry point
#
trap cleanup 0 1 2 3 6 9 14 15
#message from standart input
#because /bin/cat does not repeat its output on subsequent runs :)
TFILE="/tmp/$(basename $0).$$.tmp"
/bin/cat > $TFILE
# check what we're being called as - 'msmtpq' or 'msmtpQ'
if [ "$(/usr/bin/basename $0)" == 'msmtpQ' ] ; then # called as msmtpQ
if [ -n "$1" ] ; then # if arg(s)
check_queue # verify that queue directory is present ...
send_mail "$@" # send mail (or queue it if not connected)
exit 0
else
dsp -e 'msmtpQ requires input of a mail'
fi
fi
if [ -z "$1" ] ; then
dsp 'msmtpq requires an instruction &/or a mail'
usage
exit 1
fi
for A ; do # sort opts, args, etc.
case "$A" in
--) shift # end of msmtp opts - shift off '--'
break # anything further belongs to msmtp
;;
-h) usage # show help
exit 0
;;
-s|-sr|-e|-er|-r|-d|-m|-a) # all other valid ops
[ -z "$OP" ] && OP=${A:1} # op not already spec'd ; take all but first char (hyphen)
shift
;;
*) dsp '' "[$A] is an unknown option"
usage
exit 1
;;
esac
done
if [ -z "$OP" ] ; then # check for an empty op
dsp -e 'must specify an operation for msmtpq'
fi
check_queue # check that queue directory is present ...
while [ -n "$OP" ] ; do # while op contains a spec
case "$OP" in # sort ops ; run according to spec
s) send_mail "@" ;; # send the mail
e) enqueue_mail "$@" ;; # enqueue the mail
r) run_queue ;; # run (flush) the queue
d) display_queue ;; # display (list) all mail in queue
m) purge_a_mail ;; # purge an individual mail from queue
a) purge_all_mail ;; # purge all mail in queue
esac
OP=${OP:1} # trim off first char of OP
done
exit 0
----- End forwarded message -----
--
Best regards,
Denis Golovan aka MageSlayer