aboutsummaryrefslogtreecommitdiffstats
path: root/Mailman/Queue
diff options
context:
space:
mode:
Diffstat (limited to 'Mailman/Queue')
-rw-r--r--Mailman/Queue/CommandRunner.py18
-rw-r--r--Mailman/Queue/OutgoingRunner.py40
2 files changed, 41 insertions, 17 deletions
diff --git a/Mailman/Queue/CommandRunner.py b/Mailman/Queue/CommandRunner.py
index 785511b3..5bc1599b 100644
--- a/Mailman/Queue/CommandRunner.py
+++ b/Mailman/Queue/CommandRunner.py
@@ -140,13 +140,25 @@ Attached is your original message.
if unprocessed:
resp.append(_('\n- Unprocessed:'))
resp.extend(indent(unprocessed))
+ if not unprocessed and not self.results:
+ # The user sent an empty message; return a helpful one.
+ resp.append(Utils.wrap(_("""\
+No commands were found in this message.
+To obtain instructions, send a message containing just the word "help".
+""")))
if self.ignored:
resp.append(_('\n- Ignored:'))
resp.extend(indent(self.ignored))
resp.append(_('\n- Done.\n\n'))
- results = MIMEText(
- NL.join(resp),
- _charset=Utils.GetCharSet(self.mlist.preferred_language))
+ # Encode any unicode strings into the list charset, so we don't try to
+ # join unicode strings and invalid ASCII.
+ charset = Utils.GetCharSet(self.mlist.preferred_language)
+ encoded_resp = []
+ for item in resp:
+ if isinstance(item, UnicodeType):
+ item = item.encode(charset, 'replace')
+ encoded_resp.append(item)
+ results = MIMEText(NL.join(encoded_resp), _charset=charset)
# Safety valve for mail loops with misconfigured email 'bots. We
# don't respond to commands sent with "Precedence: bulk|junk|list"
# unless they explicitly "X-Ack: yes", but not all mail 'bots are
diff --git a/Mailman/Queue/OutgoingRunner.py b/Mailman/Queue/OutgoingRunner.py
index aed8dcb9..11c94dfe 100644
--- a/Mailman/Queue/OutgoingRunner.py
+++ b/Mailman/Queue/OutgoingRunner.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2000,2001,2002 by the Free Software Foundation, Inc.
+# Copyright (C) 2000-2003 by the Free Software Foundation, Inc.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
@@ -16,8 +16,9 @@
"""Outgoing queue runner."""
-import sys
import os
+import sys
+import copy
import time
import socket
@@ -31,9 +32,15 @@ from Mailman.Queue.Runner import Runner
from Mailman.Logging.Syslog import syslog
# This controls how often _doperiodic() will try to deal with deferred
-# permanent failures.
+# permanent failures. It is a count of calls to _doperiodic()
DEAL_WITH_PERMFAILURES_EVERY = 1
+try:
+ True, False
+except NameError:
+ True = 1
+ False = 0
+
class OutgoingRunner(Runner):
@@ -51,9 +58,13 @@ class OutgoingRunner(Runner):
# This prevents smtp server connection problems from filling up the
# error log. It gets reset if the message was successfully sent, and
# set if there was a socket.error.
- self.__logged = 0
+ self.__logged = False
def _dispose(self, mlist, msg, msgdata):
+ # See if we should retry delivery of this message again.
+ deliver_after = msgdata.get('deliver_after', 0)
+ if time.time() < deliver_after:
+ return True
# Make sure we have the most up-to-date state
mlist.Load()
try:
@@ -63,7 +74,7 @@ class OutgoingRunner(Runner):
if pid <> os.getpid():
syslog('error', 'child process leaked thru: %s', modname)
os._exit(1)
- self.__logged = 0
+ self.__logged = False
except socket.error:
# There was a problem connecting to the SMTP server. Log this
# once, but crank up our sleep time so we don't fill the error
@@ -75,8 +86,8 @@ class OutgoingRunner(Runner):
if not self.__logged:
syslog('error', 'Cannot connect to SMTP server %s on port %s',
mm_cfg.SMTPHOST, port)
- self.__logged = 1
- return 1
+ self.__logged = True
+ return True
except Errors.SomeRecipientsFailed, e:
# The delivery module being used (SMTPDirect or Sendmail) failed
# to deliver the message to one or all of the recipients.
@@ -88,14 +99,14 @@ class OutgoingRunner(Runner):
# handling. I'm not sure this is necessary, or the right thing to
# do.
pcnt = len(e.permfailures)
- copy = email.message_from_string(str(msg))
+ msgcopy = copy.deepcopy(msg)
self._permfailures.setdefault(mlist, []).extend(
- zip(e.permfailures, [copy] * pcnt))
+ zip(e.permfailures, [msgcopy] * pcnt))
# Temporary failures
if not e.tempfailures:
# Don't need to keep the message queued if there were only
# permanent failures.
- return 0
+ return False
now = time.time()
recips = e.tempfailures
last_recip_count = msgdata.get('last_recip_count', 0)
@@ -104,17 +115,18 @@ class OutgoingRunner(Runner):
# We didn't make any progress, so don't attempt delivery any
# longer. BAW: is this the best disposition?
if now > deliver_until:
- return 0
+ return False
else:
- # Keep trying to delivery this for 3 days
+ # Keep trying to delivery this message for a while
deliver_until = now + mm_cfg.DELIVERY_RETRY_PERIOD
msgdata['last_recip_count'] = len(recips)
msgdata['deliver_until'] = deliver_until
+ msgdata['deliver_after'] = now + mm_cfg.DELIVERY_RETRY_WAIT
msgdata['recips'] = recips
# Requeue
- return 1
+ return True
# We've successfully completed handling of this message
- return 0
+ return False
def _doperiodic(self):
# Periodically try to acquire the list lock and clear out the