aboutsummaryrefslogtreecommitdiffstats
path: root/Mailman/Handlers/Sendmail.py
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--Mailman/Handlers/Sendmail.py116
1 files changed, 116 insertions, 0 deletions
diff --git a/Mailman/Handlers/Sendmail.py b/Mailman/Handlers/Sendmail.py
new file mode 100644
index 00000000..8bd88697
--- /dev/null
+++ b/Mailman/Handlers/Sendmail.py
@@ -0,0 +1,116 @@
+# Copyright (C) 1998,1999,2000,2001,2002 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
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+"""Deliver a message via command-line drop-off.
+
+WARNING WARNING WARNING: This module is provided for example purposes only.
+It should not be used in a production environment for reasons described
+below. Because of this, you must explicitly enable it with by editing the
+code. See the WARN section in the process() function.
+
+This module delivers the message via the command line interface to the
+sendmail program. It should work for sendmail clones like Postfix. It is
+expected that sendmail handles final delivery, message queueing, etc. The
+recipient list is only trivially split so that the command line is less than
+about 3k in size.
+
+SECURITY WARNING: Because this module uses os.popen(), it goes through the
+shell. This module does not scan the arguments for potential exploits and so
+it should be considered unsafe for production use. For performance reasons,
+it's not recommended either -- use the SMTPDirect delivery module instead,
+even if you're using the sendmail MTA.
+
+DUPLICATES WARNING: Using this module can cause duplicates to be delivered to
+your membership, depending on your MTA! E.g. It is known that if you're using
+the sendmail MTA, and if a message contains a single dot on a line by itself,
+your list members will receive many duplicates.
+"""
+
+import string
+import os
+
+from Mailman import mm_cfg
+from Mailman import Errors
+from Mailman.Logging.Syslog import syslog
+
+MAX_CMDLINE = 3000
+
+
+
+def process(mlist, msg, msgdata):
+ """Process the message object for the given list.
+
+ The message object is an instance of Mailman.Message and must be fully
+ prepared for delivery (i.e. all the appropriate headers must be set). The
+ message object can have the following attributes:
+
+ recips - the list of recipients for the message (required)
+
+ This function processes the message by handing off the delivery of the
+ message to a sendmail (or sendmail clone) program. It can raise a
+ SendmailHandlerError if an error status was returned by the sendmail
+ program.
+
+ """
+ # WARN: If you've read the warnings above and /still/ insist on using this
+ # module, you must comment out the following line. I still recommend you
+ # don't do this!
+ assert 0, 'Use of the Sendmail.py delivery module is highly discouraged'
+ recips = msgdata.get('recips')
+ if not recips:
+ # Nobody to deliver to!
+ return
+ # Use -f to set the envelope sender
+ cmd = mm_cfg.SENDMAIL_CMD + ' -f ' + mlist.GetBouncesEmail() + ' '
+ # make sure the command line is of a manageable size
+ recipchunks = []
+ currentchunk = []
+ chunklen = 0
+ for r in recips:
+ currentchunk.append(r)
+ chunklen = chunklen + len(r) + 1
+ if chunklen > MAX_CMDLINE:
+ recipchunks.append(string.join(currentchunk))
+ currentchunk = []
+ chunklen = 0
+ # pick up the last one
+ if chunklen:
+ recipchunks.append(string.join(currentchunk))
+ # get all the lines of the message, since we're going to do this over and
+ # over again
+ msgtext = str(msg)
+ msglen = len(msgtext)
+ # cycle through all chunks
+ failedrecips = []
+ for chunk in recipchunks:
+ # TBD: SECURITY ALERT. This invokes the shell!
+ fp = os.popen(cmd + chunk, 'w')
+ fp.write(msgtext)
+ status = fp.close()
+ if status:
+ errcode = (status & 0xff00) >> 8
+ syslog('post', 'post to %s from %s, size=%d, failure=%d',
+ mlist.internal_name(), msg.get_sender(),
+ msglen, errcode)
+ # TBD: can we do better than this? What if only one recipient out
+ # of the entire chunk failed?
+ failedrecips.append(chunk)
+ # Log the successful post
+ syslog('post', 'post to %s from %s, size=%d, success',
+ mlist.internal_name(), msg.get_sender(), msglen)
+ if failedrecips:
+ msgdata['recips'] = failedrecips
+ raise Errors.SomeRecipientsFailed