Commit f1a28d01 authored by Lennart Regebro's avatar Lennart Regebro

Merging fix for collector issue #177 ( bcc-header handling, etc ) into Trunk.

parent 0ece22d9
...@@ -11,9 +11,8 @@ ...@@ -11,9 +11,8 @@
# #
############################################################################## ##############################################################################
"""SMTP mail objects """SMTP mail objects
$Id: MailHost.py,v 1.71 2002/03/20 17:47:48 Torped Exp $"""
$Id: MailHost.py,v 1.70 2002/03/11 15:54:38 andreasjung Exp $""" __version__ = "$Revision: 1.71 $"[11:-2]
__version__ = "$Revision: 1.70 $"[11:-2]
from Globals import Persistent, DTMLFile, InitializeClass from Globals import Persistent, DTMLFile, InitializeClass
from smtplib import SMTP from smtplib import SMTP
...@@ -68,7 +67,7 @@ class MailBase(Acquisition.Implicit, OFS.SimpleItem.Item, RoleManager): ...@@ -68,7 +67,7 @@ class MailBase(Acquisition.Implicit, OFS.SimpleItem.Item, RoleManager):
self.id = id self.id = id
self.title = title self.title = title
self.smtp_host = str( smtp_host ) self.smtp_host = str( smtp_host )
self.smtp_port = str( smtp_port ) self.smtp_port = int(smtp_port)
# staying for now... (backwards compatibility) # staying for now... (backwards compatibility)
...@@ -83,8 +82,7 @@ class MailBase(Acquisition.Implicit, OFS.SimpleItem.Item, RoleManager): ...@@ -83,8 +82,7 @@ class MailBase(Acquisition.Implicit, OFS.SimpleItem.Item, RoleManager):
title=str(title) title=str(title)
smtp_host=str(smtp_host) smtp_host=str(smtp_host)
if type(smtp_port) is not type(1): smtp_port=int(smtp_port)
smtp_port=int(smtp_port)
self.title=title self.title=title
self.smtp_host=smtp_host self.smtp_host=smtp_host
...@@ -104,16 +102,9 @@ class MailBase(Acquisition.Implicit, OFS.SimpleItem.Item, RoleManager): ...@@ -104,16 +102,9 @@ class MailBase(Acquisition.Implicit, OFS.SimpleItem.Item, RoleManager):
'render a mail template, then send it...' 'render a mail template, then send it...'
mtemplate = getattr(self, messageTemplate) mtemplate = getattr(self, messageTemplate)
messageText = mtemplate(self, trueself.REQUEST) messageText = mtemplate(self, trueself.REQUEST)
messageText, mto, mfrom = _mungeHeaders( messageText, mto, mfrom)
messageText=_encode(messageText, encode) messageText=_encode(messageText, encode)
headers = extractheaders(messageText) self._send(mfrom, mto, messageText)
if mto: headers['to'] = mto
if mfrom: headers['from'] = mfrom
for requiredHeader in ('to', 'from'):
if not headers.has_key(requiredHeader):
raise MailHostError,"Message missing SMTP Header '%s'"\
% requiredHeader
self._send( headers, messageText )
if not statusTemplate: return "SEND OK" if not statusTemplate: return "SEND OK"
...@@ -127,78 +118,30 @@ class MailBase(Acquisition.Implicit, OFS.SimpleItem.Item, RoleManager): ...@@ -127,78 +118,30 @@ class MailBase(Acquisition.Implicit, OFS.SimpleItem.Item, RoleManager):
security.declareProtected( use_mailhost_services, 'send' ) security.declareProtected( use_mailhost_services, 'send' )
def send(self, messageText, mto=None, mfrom=None, subject=None, def send(self, messageText, mto=None, mfrom=None, subject=None,
encode=None): encode=None):
headers = extractheaders(messageText)
messageText = messageText.lstrip()
if not headers['subject'] and len(headers)==0:
messageText="subject: %s\n\n%s" % (subject or '[No Subject]',
messageText)
elif not headers['subject']:
messageText="subject: %s\n%s" % (subject or '[No Subject]',
messageText)
if mto:
if type(mto) is type('s'):
mto=[ x.strip() for x in mto.split(',')]
headers['to'] = filter(None, mto)
if mfrom:
headers['from'] = mfrom
for requiredHeader in ('to', 'from'):
if not headers.has_key(requiredHeader):
raise MailHostError,"Message missing SMTP Header '%s'"\
% requiredHeader
messageText=_encode(messageText, encode)
self._send( headers, messageText ) messageText, mto, mfrom = _mungeHeaders( messageText, mto, mfrom, subject)
messageText = _encode(messageText, encode)
self._send(mfrom, mto, messageText)
# This is here for backwards compatibility only. Possibly it could be used to send messages
# at a sceduled future time, or via a mail queue?
security.declareProtected( use_mailhost_services, 'scheduledSend' ) security.declareProtected( use_mailhost_services, 'scheduledSend' )
def scheduledSend(self, messageText, mto=None, mfrom=None, subject=None, scheduledSend = send
encode=None):
"""Looks like the same function as send() - scheduledSend() is nowhere
used in Zope. No idea if it is still needed/used (ajung)
"""
headers = extractheaders(messageText)
if not headers['subject']:
messageText="subject: %s\n%s" % (subject or '[No Subject]',
messageText)
if mto:
if type(mto) is type('s'):
mto=[ x.strip() for x in mto.split(',')]
headers['to'] = filter(truth, mto)
if mfrom:
headers['from'] = mfrom
for requiredHeader in ('to', 'from'):
if not headers.has_key(requiredHeader):
raise MailHostError,"Message missing SMTP Header '%s'"\
% requiredHeader
messageText=_encode(messageText, encode)
self._send( headers, messageText )
security.declareProtected( use_mailhost_services, 'simple_send' ) security.declareProtected( use_mailhost_services, 'simple_send' )
def simple_send(self, mto, mfrom, subject, body): def simple_send(self, mto, mfrom, subject, body):
body="from: %s\nto: %s\nsubject: %s\n\n%s" % ( body="From: %s\nTo: %s\nSubject: %s\n\n%s" % (
mfrom, mto, subject, body) mfrom, mto, subject, body)
headers = {}
headers['from'] = mfrom
headers['to'] = mto
self._send( headers, body ) self._send( mto, mfrom, body )
security.declarePrivate( '_send' ) security.declarePrivate( '_send' )
def _send( self, headers, body ): def _send( self, mfrom, mto, messageText ):
""" Send the message """ """ Send the message """
smtpserver = SMTP( self.smtp_host, int( self.smtp_port ) ) smtpserver = SMTP( self.smtp_host, self.smtp_port )
smtpserver.sendmail( headers['from'], headers['to'], body ) smtpserver.sendmail( mfrom, mto, messageText )
smtpserver.quit() smtpserver.quit()
...@@ -223,21 +166,45 @@ def _encode(body, encode=None): ...@@ -223,21 +166,45 @@ def _encode(body, encode=None):
mimetools.encode(mfile, newmfile, encode) mimetools.encode(mfile, newmfile, encode)
return newmfile.getvalue() return newmfile.getvalue()
def _mungeHeaders( messageText, mto=None, mfrom=None, subject=None):
def extractheaders(message): """Sets missing message headers, and deletes Bcc.
# return headers of message returns fixed message, fixed mto and fixed mfrom"""
mfile=StringIO(message.strip()) mfile=StringIO(messageText.strip())
mo=rfc822.Message(mfile) mo=rfc822.Message(mfile)
hd={} # Parameters given will *always* override headers in the messageText.
hd['to']=[] # This is so that you can't override or add to subscribers by adding them to
for header in (mo.getaddrlist('to'), # the message text.
mo.getaddrlist('cc'), if subject:
mo.getaddrlist('bcc')): mo['Subject'] = subject
if not header: continue elif not mo.getheader('Subject'):
for name, addr in header: mo['Subject'] = '[No Subject]'
hd['to'].append(addr)
if mto:
hd['from']=mo.getaddr('from')[1] if isinstance(mto, types.StringType):
hd['subject']=mo.getheader('subject') or '' mto=map(lambda x:x.strip(), mto.split(','))
return hd mo['To'] = ','.join(mto)
else:
if not mo.getheader('To'):
raise MailHostError,"Message missing SMTP Header 'To'"
mto = map(lambda x:x.strip(), mo['To'].split(','))
if mo.getheader('Cc'):
mto = mto + map(lambda x:x.strip(), mo['Cc'].split(','))
if mo.getheader('Bcc'):
mto = mto + map(lambda x:x.strip(), mo['Bcc'].split(','))
if mfrom:
mo['From'] = mfrom
else:
if mo.getheader('From') is None:
raise MailHostError,"Message missing SMTP Header 'From'"
mfrom = mo['From']
if mo.getheader('Bcc'):
mo.__delitem__('Bcc')
mo.rewindbody()
finalmessage = mo
finalmessage = mo.__str__() + '\n' + mfile.read()
mfile.close()
return finalmessage, mto, mfrom
...@@ -38,7 +38,10 @@ class MailHost: ...@@ -38,7 +38,10 @@ class MailHost:
Sends an email message. Sends an email message.
The arguments are: The arguments are:
messageText -- The body of the mail message. messageText -- The mail message. It can either be a rfc822
formed text with header fields, or just a body without any
header fields. The other arguments given will override the
header fields in the message, if they exist.
mto -- A string or list of recipient(s) of the message. mto -- A string or list of recipient(s) of the message.
......
import os, sys, unittest
import string, cStringIO, re
import ZODB, Acquisition
from Products.MailHost.MailHost import MailHostError, _mungeHeaders
class TestMailHost( unittest.TestCase ):
def testAllHeaders( self ):
msg = """To: recipient@domain.com
From: sender@domain.com
Subject: This is the subject
This is the message body."""
# No additional info
resmsg, resto, resfrom = _mungeHeaders( msg )
self.failUnless(resto == ['recipient@domain.com'])
self.failUnless(resfrom == 'sender@domain.com' )
# Add duplicated info
resmsg, resto, resfrom = _mungeHeaders( msg, 'recipient@domain.com', 'sender@domain.com', 'This is the subject' )
self.failUnless(resto == ['recipient@domain.com'])
self.failUnless(resfrom == 'sender@domain.com' )
# Add extra info
resmsg, resto, resfrom = _mungeHeaders( msg, 'recipient2@domain.com', 'sender2@domain.com', 'This is the real subject' )
self.failUnless(resto == ['recipient2@domain.com'])
self.failUnless(resfrom == 'sender2@domain.com' )
def testMissingHeaders( self ):
msg = """X-Header: Dummy header
This is the message body."""
# Doesn't specify to
self.failUnlessRaises( MailHostError, _mungeHeaders, msg, mfrom='sender@domain.com' )
# Doesn't specify from
self.failUnlessRaises( MailHostError, _mungeHeaders, msg, mto='recipient@domain.com' )
def testNoHeaders( self ):
msg = """This is the message body."""
# Doesn't specify to
self.failUnlessRaises( MailHostError, _mungeHeaders, msg, mfrom='sender@domain.com' )
# Doesn't specify from
self.failUnlessRaises( MailHostError, _mungeHeaders, msg, mto='recipient@domain.com' )
# Specify all
resmsg, resto, resfrom = _mungeHeaders( msg, 'recipient2@domain.com', 'sender2@domain.com', 'This is the real subject' )
self.failUnless(resto == ['recipient2@domain.com'])
self.failUnless(resfrom == 'sender2@domain.com' )
def test_suite():
suite = unittest.TestSuite()
suite.addTest( unittest.makeSuite( TestMailHost ) )
return suite
def main():
unittest.TextTestRunner().run(test_suite())
if __name__ == '__main__':
main()
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment