summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mailman/mta/bulk.py27
-rw-r--r--src/mailman/mta/docs/bulk.txt70
2 files changed, 89 insertions, 8 deletions
diff --git a/src/mailman/mta/bulk.py b/src/mailman/mta/bulk.py
index 5c6d8257f..2b400e8b5 100644
--- a/src/mailman/mta/bulk.py
+++ b/src/mailman/mta/bulk.py
@@ -29,7 +29,9 @@ from itertools import chain
from zope.interface import implements
+from mailman.config import config
from mailman.interfaces.mta import IMailTransportAgentDelivery
+from mailman.mta.connection import Connection
# A mapping of top-level domains to bucket numbers. The zeroth bucket is
@@ -51,18 +53,20 @@ class BulkDelivery:
implements(IMailTransportAgentDelivery)
- def __init__(self, max_recipients):
+ def __init__(self, max_recipients=None):
"""Create a bulk deliverer.
:param max_recipients: The maximum number of recipients per delivery
- chunk. Zero or less means to group all recipients into one
- chunk.
+ chunk. None, zero or less means to group all recipients into one
+ big chunk.
:type max_recipients: integer
"""
- self._max_recipients = max_recipients
-
- def deliver(self, mlist, msg, msgdata):
- """See `IMailTransportAgentDelivery`."""
+ self._max_recipients = (max_recipients
+ if max_recipients is not None
+ else 0)
+ self._connection = Connection(
+ config.mta.smtp_host, int(config.mta.smtp_port),
+ self._max_recipients)
def chunkify(self, recipients):
"""Split a set of recipients into chunks.
@@ -105,3 +109,12 @@ class BulkDelivery:
# Be sure to include the last chunk, but only if it's non-empty.
if len(chunk) > 0:
yield chunk
+
+ def deliver(self, mlist, msg, msgdata):
+ """See `IMailTransportAgentDelivery`."""
+ recipients = msgdata.get('recipients')
+ if recipients is None:
+ return
+ for recipients in self.chunkify(msgdata['recipients']):
+ self._connection.sendmail(
+ 'foo@example.com', recipients, msg.as_string())
diff --git a/src/mailman/mta/docs/bulk.txt b/src/mailman/mta/docs/bulk.txt
index 0943b276f..42c9e386a 100644
--- a/src/mailman/mta/docs/bulk.txt
+++ b/src/mailman/mta/docs/bulk.txt
@@ -18,7 +18,7 @@ The standard bulk deliverer takes as an argument the maximum number of
recipients per session. The default is to deliver the message in one chunk,
containing all recipients.
- >>> bulk = BulkDelivery(0)
+ >>> bulk = BulkDelivery()
Delivery strategies must implement the proper interface.
@@ -134,3 +134,71 @@ The final chunk will contain the outliers, .xx (1) and .zz (2).
... print address
paco@example.xx
quaq@example.zz
+
+
+Bulk delivery
+=============
+
+The set of recipients for bulk delivery comes from the message metadata. If
+there are no calculated recipients, nothing gets sent.
+
+ >>> smtpd.clear()
+ >>> mlist = create_list('test@example.com')
+ >>> msg = message_from_string("""\
+ ... From: aperson@example.org
+ ... To: test@example.com
+ ... Subject: test one
+ ... Message-ID: <aardvark>
+ ...
+ ... This is a test.
+ ... """)
+
+ >>> bulk = BulkDelivery()
+ >>> bulk.deliver(mlist, msg, {})
+ >>> len(list(smtpd.messages))
+ 0
+
+With bulk delivery and no maximum number of recipients, there will be just one
+message sent, with all the recipients packed into the envelope recipients
+(i.e. RCTP TO).
+
+ >>> recipients = set('person_{0:02d}'.format(i) for i in range(100))
+ >>> msgdata = dict(recipients=recipients)
+ >>> bulk.deliver(mlist, msg, msgdata)
+ >>> messages = list(smtpd.messages)
+ >>> len(messages)
+ 1
+ >>> print messages[0].as_string()
+ From: aperson@example.org
+ To: test@example.com
+ Subject: test one
+ Message-ID: <aardvark>
+ X-Peer: ...
+ X-MailFrom: ...
+ X-RcptTo: person_...
+ person_...
+ ...
+ <BLANKLINE>
+ This is a test.
+
+The X-RcptTo header contains the set of recipients, in random order.
+
+ >>> len(messages[0]['x-rcptto'].split(','))
+ 100
+
+When the maximum number of recipients is set to 20, 5 messages will be sent,
+each with 20 addresses in the RCPT TO header.
+
+ >>> bulk = BulkDelivery(20)
+ >>> bulk.deliver(mlist, msg, msgdata)
+ >>> messages = list(smtpd.messages)
+ >>> len(messages)
+ 5
+ >>> for message in messages:
+ ... x_rcptto = message['x-rcptto']
+ ... print 'Number of recipients:', len(x_rcptto.split(','))
+ Number of recipients: 20
+ Number of recipients: 20
+ Number of recipients: 20
+ Number of recipients: 20
+ Number of recipients: 20