--- test-mailman-2.1/Mailman/Handlers/SMTPDirect.py 2010-07-03 14:12:22.000000000 -0700 +++ test-mailman/Mailman/Handlers/SMTPDirect.py 2011-02-04 19:29:49.234375000 -0800 @@ -52,6 +52,37 @@ True = 1 False = 0 +# Throttling settings. Do not send to more than THROTTLE_LIMIT recipients +# within THROTTLE_TIME seconds. Set THROTTLE_LIMIT to 0 to not throttle. +THROTTLE_TIME = 60 +THROTTLE_LIMIT = 2000 +THROTTLE_DATA = [] + +# check throttling. Doesn't return until total recipients in THROTTLE_TIME +# <= THROTTLE_LIMIT. +# +def check_throttle(count): + global THROTTLE_DATA + if THROTTLE_LIMIT <= 0: + return + if count <= 0 or count > THROTTLE_LIMIT: + syslog('error', 'check_throttle: count=%d; THROTTLE_LIMIT=%d', + count, THROTTLE_LIMIT) + return + now = time.time() + total = 0 + THROTTLE_DATA = [(num, tim) for (num, tim) in THROTTLE_DATA + if tim > now - THROTTLE_TIME] + for num, tim in THROTTLE_DATA: + total += num + total += count + if total > THROTTLE_LIMIT: + time.sleep(THROTTLE_TIME - now + THROTTLE_DATA[0][1]) + check_throttle(count) + else: + THROTTLE_DATA.append((count, now)) + return + # Manage a connection to the SMTP server @@ -118,10 +149,14 @@ chunks = [[recip] for recip in recips] msgdata['personalize'] = 1 deliveryfunc = verpdeliver - elif mm_cfg.SMTP_MAX_RCPTS <= 0: + elif mm_cfg.SMTP_MAX_RCPTS <= 0 and (THROTTLE_LIMIT <=0 or + THROTTLE_LIMIT >= len(recips)): chunks = [recips] else: - chunks = chunkify(recips, mm_cfg.SMTP_MAX_RCPTS) + if THROTTLE_LIMIT <= 0 or THROTTLE_LIMIT > mm_cfg.SMTP_MAX_RCPTS: + chunks = chunkify(recips, mm_cfg.SMTP_MAX_RCPTS) + else: + chunks = chunkify(recips, THROTTLE_LIMIT) # See if this is an unshunted message for which some were undelivered if msgdata.has_key('undelivered'): chunks = msgdata['undelivered'] @@ -384,6 +419,8 @@ msgid = msg['message-id'] try: # Send the message + # but wait if necessary for throttling + check_throttle(len(recips)) refused = conn.sendmail(envsender, recips, msgtext) except smtplib.SMTPRecipientsRefused, e: syslog('smtp-failure', 'All recipients refused: %s, msgid: %s',