Example #1
0
    def testNonASCIIAddrs(self):
        import os
        from email.mime import base
        import transaction
        from repoze.sendmail.delivery import QueuedMailDelivery
        from repoze.sendmail._compat import b
        from repoze.sendmail._compat import text_type
        delivery = QueuedMailDelivery(self.maildir_path)

        non_ascii = b('LaPe\xc3\xb1a').decode('utf-8')
        fromaddr = non_ascii + ' <*****@*****.**>'
        toaddrs = (non_ascii + ' <*****@*****.**>', )
        message = base.MIMEBase('text', 'plain')
        message['From'] = fromaddr
        message['To'] = ','.join(toaddrs)

        delivery.send(fromaddr, toaddrs, message)
        self.assertTrue(os.listdir(os.path.join(self.maildir_path, 'tmp')))
        self.assertFalse(os.listdir(os.path.join(self.maildir_path, 'new')))
        transaction.commit()
        self.assertFalse(os.listdir(os.path.join(self.maildir_path, 'tmp')))
        self.assertTrue(os.listdir(os.path.join(self.maildir_path, 'new')))

        self.qp.send_messages()
        self.assertTrue(len(self.qp.mailer.sent_messages), 1)
        queued_fromaddr, queued_toaddrs, queued_message = (
            self.qp.mailer.sent_messages[0])
        self.assertEqual(queued_fromaddr, fromaddr)
        self.assertEqual(queued_toaddrs, toaddrs)
    def testNonASCIIAddrs(self):
        import os
        from email.mime import base
        import transaction
        from repoze.sendmail.delivery import QueuedMailDelivery
        from repoze.sendmail._compat import b
        from repoze.sendmail._compat import text_type
        delivery = QueuedMailDelivery(self.maildir_path)

        non_ascii = b('LaPe\xc3\xb1a').decode('utf-8')
        fromaddr = non_ascii+' <*****@*****.**>'
        toaddrs = (non_ascii+' <*****@*****.**>',)
        message = base.MIMEBase('text', 'plain')
        message['From'] = fromaddr
        message['To'] = ','.join(toaddrs)

        delivery.send(fromaddr, toaddrs, message)
        self.assertTrue(os.listdir(os.path.join(self.maildir_path, 'tmp')))
        self.assertFalse(os.listdir(os.path.join(self.maildir_path, 'new')))
        transaction.commit()
        self.assertFalse(os.listdir(os.path.join(self.maildir_path, 'tmp')))
        self.assertTrue(os.listdir(os.path.join(self.maildir_path, 'new')))

        self.qp.send_messages()
        self.assertTrue(len(self.qp.mailer.sent_messages), 1)
        queued_fromaddr, queued_toaddrs, queued_message = (
            self.qp.mailer.sent_messages[0])
        self.assertEqual(queued_fromaddr, fromaddr)
        self.assertEqual(queued_toaddrs, toaddrs)
    def testSend(self):
        from email.message import Message
        import transaction
        from repoze.sendmail.delivery import QueuedMailDelivery
        from repoze.sendmail._compat import text_type
        delivery = QueuedMailDelivery('/path/to/mailbox')
        fromaddr = '*****@*****.**'
        toaddrs = ('*****@*****.**',
                   '*****@*****.**')
        message = Message()
        message['From'] = 'Jim <*****@*****.**>'
        message['To'] = 'some-zope-coders:;'
        message['Date'] = 'Date: Mon, 19 May 2003 10:17:36 -0400'
        message['Message-Id'] = ext_msgid = '<*****@*****.**>'
        message['Subject'] = 'example'
        message.set_payload('This is just an example\n')

        msgid = delivery.send(fromaddr, toaddrs, message)
        self.assertEqual(msgid, '<*****@*****.**>')
        self.assertEqual(MaildirMessageStub.commited_messages, [])
        self.assertEqual(MaildirMessageStub.aborted_messages, [])
        transaction.commit()
        self.assertEqual(len(MaildirMessageStub.commited_messages), 1)
        self.assertEqual(MaildirMessageStub.aborted_messages, [])
        message = MaildirMessageStub.commited_messages[0]
        self.assertEqual(text_type(message['X-Actually-From']), fromaddr)
        self.assertEqual(text_type(
            message['X-Actually-To']), ','.join(toaddrs))

        MaildirMessageStub.commited_messages = []
        msgid = delivery.send(fromaddr, toaddrs, message)
        self.assertTrue('@' in msgid)
        self.assertEqual(MaildirMessageStub.commited_messages, [])
        self.assertEqual(MaildirMessageStub.aborted_messages, [])
        transaction.commit()
        self.assertEqual(len(MaildirMessageStub.commited_messages), 1)
        self.assertEqual(MaildirMessageStub.commited_messages[0].get_payload(),
                         'This is just an example\n')
        self.assertEqual(message['Message-Id'], msgid)
        self.assertEqual(message['Message-Id'], ext_msgid)
        self.assertEqual(MaildirMessageStub.aborted_messages, [])

        MaildirMessageStub.commited_messages = []
        msgid = delivery.send(fromaddr, toaddrs, message)
        self.assertEqual(MaildirMessageStub.commited_messages, [])
        self.assertEqual(MaildirMessageStub.aborted_messages, [])
        transaction.abort()
        self.assertEqual(MaildirMessageStub.commited_messages, [])
        self.assertEqual(len(MaildirMessageStub.aborted_messages), 1)
Example #4
0
    def testSend(self):
        from email.message import Message
        import transaction
        from repoze.sendmail.delivery import QueuedMailDelivery
        from repoze.sendmail._compat import text_type
        delivery = QueuedMailDelivery('/path/to/mailbox')
        fromaddr = '*****@*****.**'
        toaddrs = ('*****@*****.**', '*****@*****.**')
        message = Message()
        message['From'] = 'Jim <*****@*****.**>'
        message['To'] = 'some-zope-coders:;'
        message['Date'] = 'Date: Mon, 19 May 2003 10:17:36 -0400'
        message['Message-Id'] = ext_msgid = '<*****@*****.**>'
        message['Subject'] = 'example'
        message.set_payload('This is just an example\n')

        msgid = delivery.send(fromaddr, toaddrs, message)
        self.assertEqual(msgid, '<*****@*****.**>')
        self.assertEqual(MaildirMessageStub.commited_messages, [])
        self.assertEqual(MaildirMessageStub.aborted_messages, [])
        transaction.commit()
        self.assertEqual(len(MaildirMessageStub.commited_messages), 1)
        self.assertEqual(MaildirMessageStub.aborted_messages, [])
        message = MaildirMessageStub.commited_messages[0]
        self.assertEqual(text_type(message['X-Actually-From']), fromaddr)
        self.assertEqual(text_type(message['X-Actually-To']),
                         ','.join(toaddrs))

        MaildirMessageStub.commited_messages = []
        msgid = delivery.send(fromaddr, toaddrs, message)
        self.assertTrue('@' in msgid)
        self.assertEqual(MaildirMessageStub.commited_messages, [])
        self.assertEqual(MaildirMessageStub.aborted_messages, [])
        transaction.commit()
        self.assertEqual(len(MaildirMessageStub.commited_messages), 1)
        self.assertEqual(MaildirMessageStub.commited_messages[0].get_payload(),
                         'This is just an example\n')
        self.assertEqual(message['Message-Id'], msgid)
        self.assertEqual(message['Message-Id'], ext_msgid)
        self.assertEqual(MaildirMessageStub.aborted_messages, [])

        MaildirMessageStub.commited_messages = []
        msgid = delivery.send(fromaddr, toaddrs, message)
        self.assertEqual(MaildirMessageStub.commited_messages, [])
        self.assertEqual(MaildirMessageStub.aborted_messages, [])
        transaction.abort()
        self.assertEqual(MaildirMessageStub.commited_messages, [])
        self.assertEqual(len(MaildirMessageStub.aborted_messages), 1)
Example #5
0
    def testNonASCIIAddrs(self):
        from email.message import Message
        from repoze.sendmail.delivery import QueuedMailDelivery
        delivery = QueuedMailDelivery('/path/to/mailbox')

        non_ascii = b('LaPe\xc3\xb1a').decode('utf-8')
        fromaddr = non_ascii+' <*****@*****.**>'
        toaddrs = (non_ascii+' <*****@*****.**>',)
        message = Message()

        delivery.send(fromaddr, toaddrs, message)
        transaction.commit()
        message = MaildirMessageStub.commited_messages[0]

        self.assertEqual(raw_header(message['X-Actually-From']), fromaddr)
        self.assertEqual(raw_header(
            message['X-Actually-To']), ','.join(toaddrs))
    def testSend(self):
        from repoze.sendmail.delivery import QueuedMailDelivery
        delivery = QueuedMailDelivery('/path/to/mailbox')
        fromaddr = '*****@*****.**'
        toaddrs = ('*****@*****.**',
                   'steve@examplecom')
        zope_headers = ('X-Zope-From: [email protected]\n'
                       'X-Zope-To: [email protected], steve@examplecom\n')
        opt_headers = ('From: Jim <*****@*****.**>\n'
                       'To: some-zope-coders:;\n'
                       'Date: Mon, 19 May 2003 10:17:36 -0400\n'
                       'Message-Id: <*****@*****.**>\n')
        message =     ('Subject: example\n'
                       '\n'
                       'This is just an example\n')

        msgid = delivery.send(fromaddr, toaddrs, opt_headers + message)
        self.assertEquals(msgid, '*****@*****.**')
        self.assertEquals(MaildirWriterStub.commited_messages, [])
        self.assertEquals(MaildirWriterStub.aborted_messages, [])
        transaction.commit()
        self.assertEquals(MaildirWriterStub.commited_messages,
                          [zope_headers + opt_headers + message])
        self.assertEquals(MaildirWriterStub.aborted_messages, [])

        MaildirWriterStub.commited_messages = []
        msgid = delivery.send(fromaddr, toaddrs, message)
        self.assert_('@' in msgid)
        self.assertEquals(MaildirWriterStub.commited_messages, [])
        self.assertEquals(MaildirWriterStub.aborted_messages, [])
        transaction.commit()
        self.assertEquals(len(MaildirWriterStub.commited_messages), 1)
        self.assert_(MaildirWriterStub.commited_messages[0].endswith(message))
        new_headers = MaildirWriterStub.commited_messages[0][:-len(message)]
        self.assert_(new_headers.find('Message-Id: <%s>' % msgid) != -1)
        self.assert_(new_headers.find('X-Zope-From: %s' % fromaddr) != 1)
        self.assert_(new_headers.find('X-Zope-To: %s' % ", ".join(toaddrs)) != 1)
        self.assertEquals(MaildirWriterStub.aborted_messages, [])

        MaildirWriterStub.commited_messages = []
        msgid = delivery.send(fromaddr, toaddrs, opt_headers + message)
        self.assertEquals(MaildirWriterStub.commited_messages, [])
        self.assertEquals(MaildirWriterStub.aborted_messages, [])
        transaction.abort()
        self.assertEquals(MaildirWriterStub.commited_messages, [])
        self.assertEquals(len(MaildirWriterStub.aborted_messages), 1)
    def test_send(self):
        import transaction
        from repoze.sendmail.delivery import QueuedMailDelivery
        from repoze.sendmail._compat import text_type
        delivery = QueuedMailDelivery('/path/to/mailbox')
        fromaddr = '*****@*****.**'
        toaddrs = ('*****@*****.**',
                   '*****@*****.**')

        message = self._makeMessage()
        msgid = delivery.send(fromaddr, toaddrs, message)
        self.assertEqual(msgid, '<*****@*****.**>')
        self.assertEqual(MaildirMessageStub.commited_messages, [])
        self.assertEqual(MaildirMessageStub.aborted_messages, [])
        transaction.commit()
        self.assertEqual(len(MaildirMessageStub.commited_messages), 1)
        self.assertEqual(MaildirMessageStub.aborted_messages, [])
        message = MaildirMessageStub.commited_messages[0]
        self.assertEqual(text_type(message['X-Actually-From']), fromaddr)
        self.assertEqual(text_type(
            message['X-Actually-To']), ','.join(toaddrs))

        MaildirMessageStub.commited_messages = []
        message = self._makeMessage()
        msgid = delivery.send(fromaddr, toaddrs, message)
        self.assertTrue('@' in msgid)
        self.assertEqual(MaildirMessageStub.commited_messages, [])
        self.assertEqual(MaildirMessageStub.aborted_messages, [])
        transaction.commit()
        self.assertEqual(len(MaildirMessageStub.commited_messages), 1)
        self.assertEqual(MaildirMessageStub.commited_messages[0].get_payload(),
                         'This is just an example\n')
        self.assertEqual(message['Message-Id'], msgid)
        self.assertEqual(message['Message-Id'], '<*****@*****.**>')
        self.assertEqual(MaildirMessageStub.aborted_messages, [])

        MaildirMessageStub.commited_messages = []
        message = self._makeMessage()
        msgid = delivery.send(fromaddr, toaddrs, message)
        self.assertEqual(MaildirMessageStub.commited_messages, [])
        self.assertEqual(MaildirMessageStub.aborted_messages, [])
        transaction.abort()
        self.assertEqual(MaildirMessageStub.commited_messages, [])
        self.assertEqual(len(MaildirMessageStub.aborted_messages), 1)
    def testSend(self):
        from repoze.sendmail.delivery import QueuedMailDelivery
        delivery = QueuedMailDelivery('/path/to/mailbox')
        fromaddr = '*****@*****.**'
        toaddrs = ('*****@*****.**', 'steve@examplecom')
        zope_headers = ('X-Zope-From: [email protected]\n'
                        'X-Zope-To: [email protected], steve@examplecom\n')
        opt_headers = ('From: Jim <*****@*****.**>\n'
                       'To: some-zope-coders:;\n'
                       'Date: Mon, 19 May 2003 10:17:36 -0400\n'
                       'Message-Id: <*****@*****.**>\n')
        message = ('Subject: example\n' '\n' 'This is just an example\n')

        msgid = delivery.send(fromaddr, toaddrs, opt_headers + message)
        self.assertEquals(msgid, '*****@*****.**')
        self.assertEquals(MaildirWriterStub.commited_messages, [])
        self.assertEquals(MaildirWriterStub.aborted_messages, [])
        transaction.commit()
        self.assertEquals(MaildirWriterStub.commited_messages,
                          [zope_headers + opt_headers + message])
        self.assertEquals(MaildirWriterStub.aborted_messages, [])

        MaildirWriterStub.commited_messages = []
        msgid = delivery.send(fromaddr, toaddrs, message)
        self.assert_('@' in msgid)
        self.assertEquals(MaildirWriterStub.commited_messages, [])
        self.assertEquals(MaildirWriterStub.aborted_messages, [])
        transaction.commit()
        self.assertEquals(len(MaildirWriterStub.commited_messages), 1)
        self.assert_(MaildirWriterStub.commited_messages[0].endswith(message))
        new_headers = MaildirWriterStub.commited_messages[0][:-len(message)]
        self.assert_(new_headers.find('Message-Id: <%s>' % msgid) != -1)
        self.assert_(new_headers.find('X-Zope-From: %s' % fromaddr) != 1)
        self.assert_(
            new_headers.find('X-Zope-To: %s' % ", ".join(toaddrs)) != 1)
        self.assertEquals(MaildirWriterStub.aborted_messages, [])

        MaildirWriterStub.commited_messages = []
        msgid = delivery.send(fromaddr, toaddrs, opt_headers + message)
        self.assertEquals(MaildirWriterStub.commited_messages, [])
        self.assertEquals(MaildirWriterStub.aborted_messages, [])
        transaction.abort()
        self.assertEquals(MaildirWriterStub.commited_messages, [])
        self.assertEquals(len(MaildirWriterStub.aborted_messages), 1)
Example #9
0
    def test_send(self):
        import transaction
        from repoze.sendmail.delivery import QueuedMailDelivery
        from repoze.sendmail._compat import text_type
        delivery = QueuedMailDelivery('/path/to/mailbox')
        fromaddr = '*****@*****.**'
        toaddrs = ('*****@*****.**',
                   '*****@*****.**')

        message = self._makeMessage()
        msgid = delivery.send(fromaddr, toaddrs, message)
        self.assertEqual(msgid, '<*****@*****.**>')
        self.assertEqual(MaildirMessageStub.commited_messages, [])
        self.assertEqual(MaildirMessageStub.aborted_messages, [])
        transaction.commit()
        self.assertEqual(len(MaildirMessageStub.commited_messages), 1)
        self.assertEqual(MaildirMessageStub.aborted_messages, [])
        message = MaildirMessageStub.commited_messages[0]
        self.assertEqual(text_type(message['X-Actually-From']), fromaddr)
        self.assertEqual(text_type(
            message['X-Actually-To']), ','.join(toaddrs))

        MaildirMessageStub.commited_messages = []
        message = self._makeMessage()
        msgid = delivery.send(fromaddr, toaddrs, message)
        self.assertTrue('@' in msgid)
        self.assertEqual(MaildirMessageStub.commited_messages, [])
        self.assertEqual(MaildirMessageStub.aborted_messages, [])
        transaction.commit()
        self.assertEqual(len(MaildirMessageStub.commited_messages), 1)
        self.assertEqual(MaildirMessageStub.commited_messages[0].get_payload(),
                         'This is just an example\n')
        self.assertEqual(message['Message-Id'], msgid)
        self.assertEqual(message['Message-Id'], '<*****@*****.**>')
        self.assertEqual(MaildirMessageStub.aborted_messages, [])

        MaildirMessageStub.commited_messages = []
        message = self._makeMessage()
        msgid = delivery.send(fromaddr, toaddrs, message)
        self.assertEqual(MaildirMessageStub.commited_messages, [])
        self.assertEqual(MaildirMessageStub.aborted_messages, [])
        transaction.abort()
        self.assertEqual(MaildirMessageStub.commited_messages, [])
        self.assertEqual(len(MaildirMessageStub.aborted_messages), 1)
Example #10
0
    def test_send(self):
        import transaction
        from repoze.sendmail.delivery import QueuedMailDelivery
        from repoze.sendmail._compat import text_type

        delivery = QueuedMailDelivery("/path/to/mailbox")
        fromaddr = "*****@*****.**"
        toaddrs = ("*****@*****.**", "*****@*****.**")

        message = self._makeMessage()
        msgid = delivery.send(fromaddr, toaddrs, message)
        self.assertEqual(msgid, "<*****@*****.**>")
        self.assertEqual(MaildirMessageStub.commited_messages, [])
        self.assertEqual(MaildirMessageStub.aborted_messages, [])
        transaction.commit()
        self.assertEqual(len(MaildirMessageStub.commited_messages), 1)
        self.assertEqual(MaildirMessageStub.aborted_messages, [])
        message = MaildirMessageStub.commited_messages[0]
        self.assertEqual(text_type(message["X-Actually-From"]), fromaddr)
        self.assertEqual(text_type(message["X-Actually-To"]), ",".join(toaddrs))

        MaildirMessageStub.commited_messages = []
        message = self._makeMessage()
        msgid = delivery.send(fromaddr, toaddrs, message)
        self.assertTrue("@" in msgid)
        self.assertEqual(MaildirMessageStub.commited_messages, [])
        self.assertEqual(MaildirMessageStub.aborted_messages, [])
        transaction.commit()
        self.assertEqual(len(MaildirMessageStub.commited_messages), 1)
        self.assertEqual(MaildirMessageStub.commited_messages[0].get_payload(), "This is just an example\n")
        self.assertEqual(message["Message-Id"], msgid)
        self.assertEqual(message["Message-Id"], "<*****@*****.**>")
        self.assertEqual(MaildirMessageStub.aborted_messages, [])

        MaildirMessageStub.commited_messages = []
        message = self._makeMessage()
        msgid = delivery.send(fromaddr, toaddrs, message)
        self.assertEqual(MaildirMessageStub.commited_messages, [])
        self.assertEqual(MaildirMessageStub.aborted_messages, [])
        transaction.abort()
        self.assertEqual(MaildirMessageStub.commited_messages, [])
        self.assertEqual(len(MaildirMessageStub.aborted_messages), 1)
Example #11
0
File: mailer.py Project: zagy/karl
 def bounce(self, mto, msg):
     QueuedMailDelivery.send(self, self.bounce_from, mto, msg)
Example #12
0
File: mailer.py Project: zagy/karl
 def send(self, mto, msg):
     QueuedMailDelivery.send(self, self.mfrom, mto, msg)
Example #13
0
class Mailer(object):
    """
    Manages sending of email messages.

    :param host: SMTP hostname
    :param port: SMTP port
    :param username: SMTP username
    :param password: SMPT password
    :param tls: use TLS
    :param ssl: use SSL
    :param keyfile: SSL key file 
    :param certfile: SSL certificate file
    :param queue_path: path to maildir for queued messages
    :param default_sender: default "from" address
    :param sendmail_app: path to "sendmail" binary.
           repoze defaults to "/usr/sbin/sendmail"
    :param sendmail_template: custom commandline template passed to sendmail
           binary, defaults to'["{sendmail_app}", "-t", "-i", "-f", "{sender}"]'
    :param debug: SMTP debug level
    """

    def __init__(self, 
                 host='localhost', 
                 port=25, 
                 username=None,
                 password=None, 
                 tls=False,
                 ssl=False,
                 keyfile=None,
                 certfile=None,
                 queue_path=None,
                 default_sender=None,
                 sendmail_app=None,
                 sendmail_template=None,
                 debug=0):


        if ssl:

            self.smtp_mailer = SMTP_SSLMailer(
                hostname=host,
                port=port,
                username=username,
                password=password,
                no_tls=not(tls),
                force_tls=tls,
                debug_smtp=debug,
                keyfile=keyfile,
                certfile=certfile)

        else:

            self.smtp_mailer = SMTPMailer(
                hostname=host, 
                port=port, 
                username=username, 
                password=password, 
                no_tls=not(tls), 
                force_tls=tls, 
                debug_smtp=debug)

        self.direct_delivery = DirectMailDelivery(self.smtp_mailer)

        if queue_path:
            self.queue_delivery = QueuedMailDelivery(queue_path)
        else:
            self.queue_delivery = None
            
        self.sendmail_mailer = SendmailMailer(sendmail_app, sendmail_template)
        self.sendmail_delivery = DirectMailDelivery(self.sendmail_mailer)

        self.default_sender = default_sender

    @classmethod
    def from_settings(cls, settings, prefix='mail.'):
        """
        Creates a new instance of **Mailer** from settings dict.

        :param settings: a settings dict-like
        :param prefix: prefix separating **pyramid_mailer** settings
        """

        settings = settings or {}

        kwarg_names = [prefix + k for k in (
                       'host', 'port', 'username',
                       'password', 'tls', 'ssl', 'keyfile', 
                       'certfile', 'queue_path', 'debug', 'default_sender')]
        
        size = len(prefix)

        kwargs = dict(((k[size:], settings[k]) for k in settings.keys() if
                        k in kwarg_names))

        for key in ('tls', 'ssl'):
            val = kwargs.get(key)
            if val:
                kwargs[key] = asbool(val)

        return cls(**kwargs)

    def send(self, message):
        """
        Sends a message. The message is handled inside a transaction, so 
        in case of failure (or the message fails) the message will not be sent.

        :param message: a **Message** instance.
        """

        return self.direct_delivery.send(*self._message_args(message))

    def send_immediately(self, message, fail_silently=False):
        """
        Sends a message immediately, outside the transaction manager. 

        If there is a connection error to the mail server this will have to 
        be handled manually. However if you pass ``fail_silently`` the error
        will be swallowed.

        :versionadded: 0.3

        :param message: a **Message** instance.

        :param fail_silently: silently handle connection errors.
        """

        try:
            return self.smtp_mailer.send(*self._message_args(message))
        except smtplib.socket.error:
            if not fail_silently:
                raise

    def send_to_queue(self, message):
        """
        Adds a message to a maildir queue.
        
        In order to handle this, the setting **mail.queue_path** must be 
        provided and must point to a valid maildir.

        :param message: a **Message** instance.
        """

        if not self.queue_delivery:
            raise RuntimeError("No queue_path provided")
    
        return self.queue_delivery.send(*self._message_args(message))

    def _message_args(self, message):

        message.sender = message.sender or self.default_sender
        # convert Lamson message to Python email package msessage
        msg = message.to_message() 
        return (message.sender, message.send_to, msg)

    def send_sendmail(self, message ):
        """
        Sends a message within the transaction manager.

        Uses the local sendmail option

        :param message: a **Message** instance.
        """
        return self.sendmail_delivery.send(*self._message_args(message))

    def send_immediately_sendmail(self, message, fail_silently=False):
        """
        Sends a message immediately, outside the transaction manager.

        Uses the local sendmail option

        If there is a connection error to the mail server this will have to
        be handled manually. However if you pass ``fail_silently`` the error
        will be swallowed.

        :param message: a **Message** instance.

        :param fail_silently: silently handle connection errors.
        """

        try:
            return self.sendmail_mailer.send(*self._message_args(message))
        except:
            if not fail_silently:
                raise
Example #14
0
class Mailer(object):
    """Manages sending of email messages.

    :param host: SMTP hostname
    :param port: SMTP port
    :param username: SMTP username
    :param password: SMPT password
    :param tls: use TLS
    :param ssl: use SSL
    :param keyfile: SSL key file
    :param certfile: SSL certificate file
    :param queue_path: path to maildir for queued messages
    :param default_sender: default "from" address
    :param sendmail_app: path to "sendmail" binary.
           repoze defaults to "/usr/sbin/sendmail"
    :param sendmail_template: custom commandline template passed to sendmail
           binary, defaults to'["{sendmail_app}", "-t", "-i", "-f", "{sender}"]'
    :param debug: SMTP debug level
    """

    def __init__(self,
                 host='localhost',
                 port=25,
                 username=None,
                 password=None,
                 tls=False,
                 ssl=False,
                 keyfile=None,
                 certfile=None,
                 queue_path=None,
                 default_sender=None,
                 sendmail_app=None,
                 sendmail_template=None,
                 debug=0):
        if ssl:
            self.smtp_mailer = SMTP_SSLMailer(
                hostname=host,
                port=port,
                username=username,
                password=password,
                no_tls=not(tls),
                force_tls=tls,
                debug_smtp=debug,
                keyfile=keyfile,
                certfile=certfile)
        else:
            self.smtp_mailer = SMTPMailer(
                hostname=host,
                port=port,
                username=username,
                password=password,
                no_tls=not(tls),
                force_tls=tls,
                debug_smtp=debug)

        self.direct_delivery = DirectMailDelivery(self.smtp_mailer)

        if queue_path:
            self.queue_delivery = QueuedMailDelivery(queue_path)
        else:
            self.queue_delivery = None

        self.sendmail_mailer = SendmailMailer(sendmail_app, sendmail_template)
        self.sendmail_delivery = DirectMailDelivery(self.sendmail_mailer)
        self.default_sender = default_sender

    @classmethod
    def from_settings(cls, settings, prefix='mail.'):
        """Create a new instance of 'Mailer' from settings dict.

        :param settings: a settings dict-like
        :param prefix: prefix separating 'pyramid_mailer' settings
        """
        settings = settings or {}

        kwarg_names = [prefix + k for k in (
                       'host', 'port', 'username',
                       'password', 'tls', 'ssl', 'keyfile',
                       'certfile', 'queue_path', 'debug', 'default_sender')]

        size = len(prefix)

        kwargs = dict(((k[size:], settings[k]) for k in settings.keys() if
                        k in kwarg_names))

        for key in ('tls', 'ssl'):
            val = kwargs.get(key)
            if val:
                kwargs[key] = asbool(val)

        return cls(**kwargs)

    def send(self, message):
        """Send a message.

        The message is handled inside a transaction, so in case of failure
        (or the message fails) the message will not be sent.

        :param message: a 'Message' instance.
        """
        return self.direct_delivery.send(*self._message_args(message))

    def send_immediately(self, message, fail_silently=False):
        """Send a message immediately, outside the transaction manager.

        If there is a connection error to the mail server this will have to
        be handled manually. However if you pass ``fail_silently`` the error
        will be swallowed.

        :versionadded: 0.3

        :param message: a 'Message' instance.

        :param fail_silently: silently handle connection errors.
        """
        try:
            return self.smtp_mailer.send(*self._message_args(message))
        except smtplib.socket.error:
            if not fail_silently:
                raise

    def send_to_queue(self, message):
        """Add a message to a maildir queue.

        In order to handle this, the setting 'mail.queue_path' must be
        provided and must point to a valid maildir.

        :param message: a 'Message' instance.
        """
        if not self.queue_delivery:
            raise RuntimeError("No queue_path provided")

        return self.queue_delivery.send(*self._message_args(message))

    def _message_args(self, message):

        message.sender = message.sender or self.default_sender
        # convert Lamson message to Python email package msessage
        msg = message.to_message()
        return (message.sender, message.send_to, msg)

    def send_sendmail(self, message ):
        """Send a message within the transaction manager.

        Uses the local sendmail option

        :param message: a 'Message' instance.
        """
        return self.sendmail_delivery.send(*self._message_args(message))

    def send_immediately_sendmail(self, message, fail_silently=False):
        """Send a message immediately, outside the transaction manager.

        Uses the local sendmail option

        If there is a connection error to the mail server this will have to
        be handled manually. However if you pass ``fail_silently`` the error
        will be swallowed.

        :param message: a 'Message' instance.

        :param fail_silently: silently handle connection errors.
        """
        try:
            return self.sendmail_mailer.send(*self._message_args(message))
        except:
            if not fail_silently:
                raise
Example #15
0
class TestConsoleApp(TestCase):
    def setUp(self):
        from repoze.sendmail.delivery import QueuedMailDelivery
        from repoze.sendmail.maildir import Maildir
        self.dir = mkdtemp()
        self.queue_dir = os.path.join(self.dir, "queue")
        self.delivery = QueuedMailDelivery(self.queue_dir)
        self.maildir = Maildir(self.queue_dir, True)
        self.mailer = _makeMailerStub()

        self.save_stderr = sys.stderr
        sys.stderr = self.stderr = StringIO()

    def tearDown(self):
        sys.stderr = self.save_stderr
        shutil.rmtree(self.dir)

    def _captureLoggedErrors(self, cmdline):
        from repoze.sendmail import queue
        logged = []
        monkey = _Monkey(queue, _log_error=logged.append)
        # py 25 compat, can't use with statement
        exc_info = ()
        try:
            monkey.__enter__()
            app = ConsoleApp(cmdline.split())
        except:  # pragma: no cover
            exc_info = sys.exc_info()
        monkey.__exit__(*exc_info)
        return app, logged

    def test_args_simple_ok(self):
        # Simplest case that works
        cmdline = "qp %s" % self.dir
        app = ConsoleApp(cmdline.split())
        self.assertEqual("qp", app.script_name)
        self.assertFalse(app._error)
        self.assertEqual(self.dir, app.queue_path)
        self.assertEqual("localhost", app.hostname)
        self.assertEqual(25, app.port)
        self.assertEqual(None, app.username)
        self.assertEqual(None, app.password)
        self.assertFalse(app.force_tls)
        self.assertFalse(app.no_tls)
        self.assertFalse(app.debug_smtp)

    def test_args_simple_error(self):
        # Simplest case that doesn't work
        cmdline = "qp"
        app, logged = self._captureLoggedErrors(cmdline)
        self.assertEqual("qp", app.script_name)
        self.assertTrue(app._error)
        self.assertEqual(None, app.queue_path)
        self.assertEqual("localhost", app.hostname)
        self.assertEqual(25, app.port)
        self.assertEqual(None, app.username)
        self.assertEqual(None, app.password)
        self.assertFalse(app.force_tls)
        self.assertFalse(app.no_tls)
        self.assertFalse(app.debug_smtp)
        self.assertEqual(len(logged), 1)
        app.main()

    def test_args_full_monty(self):
        # Use (almost) all of the options
        cmdline = """qp --hostname foo --port 75
                        --username chris --password rossi --force-tls
                        --debug-smtp --ssl
                        %s""" % self.dir
        app = ConsoleApp(cmdline.split())
        self.assertEqual("qp", app.script_name)
        self.assertFalse(app._error)
        self.assertEqual(self.dir, app.queue_path)
        self.assertEqual("foo", app.hostname)
        self.assertEqual(75, app.port)
        self.assertEqual("chris", app.username)
        self.assertEqual("rossi", app.password)
        self.assertTrue(app.force_tls)
        self.assertTrue(app.ssl)
        self.assertFalse(app.no_tls)
        self.assertTrue(app.debug_smtp)

    def test_args_username_no_password(self):
        # Test username without password
        cmdline = "qp --username chris %s" % self.dir
        app, logged = self._captureLoggedErrors(cmdline)
        self.assertTrue(app._error)
        self.assertEqual(len(logged), 1)

    def test_args_force_tls_no_tls(self):
        # Test force_tls and no_tls
        cmdline = "qp --force-tls --no-tls %s" % self.dir
        app, logged = self._captureLoggedErrors(cmdline)
        self.assertTrue(app._error)
        self.assertEqual(len(logged), 1)

    def test_args_hostname_no_hostname(self):
        cmdline = 'qp %s --hostname' % self.dir
        app, logged = self._captureLoggedErrors(cmdline)
        self.assertTrue(app._error)
        self.assertEqual(len(logged), 1)

    def test_args_port_no_port(self):
        cmdline = 'qp %s --port' % self.dir
        app, logged = self._captureLoggedErrors(cmdline)
        self.assertTrue(app._error)
        self.assertEqual(len(logged), 1)

    def test_args_bad_port(self):
        cmdline = 'qp %s --port foo' % self.dir
        app, logged = self._captureLoggedErrors(cmdline)
        self.assertTrue(app._error)
        self.assertEqual(len(logged), 1)

    def test_args_username_no_username(self):
        cmdline = 'qp %s --username' % self.dir
        app, logged = self._captureLoggedErrors(cmdline)
        self.assertTrue(app._error)
        self.assertEqual(len(logged), 1)

    def test_args_password_no_password(self):
        cmdline = 'qp %s --password' % self.dir
        app, logged = self._captureLoggedErrors(cmdline)
        self.assertTrue(app._error)
        self.assertEqual(len(logged), 1)

    def test_args_config_no_config(self):
        cmdline = 'qp %s --config' % self.dir
        app, logged = self._captureLoggedErrors(cmdline)
        self.assertTrue(app._error)
        self.assertEqual(len(logged), 1)

    def test_args_bad_arg(self):
        cmdline = 'qp --foo %s' % self.dir
        app, logged = self._captureLoggedErrors(cmdline)
        self.assertTrue(app._error)
        self.assertEqual(len(logged), 1)

    def test_args_too_many_queues(self):
        cmdline = 'qp %s foobar' % self.dir
        app, logged = self._captureLoggedErrors(cmdline)
        self.assertTrue(app._error)
        self.assertEqual(len(logged), 1)

    def test_ini_parse(self):
        ini_path = os.path.join(self.dir, "qp.ini")
        f = open(ini_path, "w")
        f.write(test_ini)
        f.close()

        # Override most everything
        cmdline = """qp --config %s""" % ini_path
        app = ConsoleApp(cmdline.split())
        self.assertEqual("qp", app.script_name)
        self.assertFalse(app._error)
        self.assertEqual("hammer/dont/hurt/em", app.queue_path)
        self.assertEqual("testhost", app.hostname)
        self.assertEqual(2525, app.port)
        self.assertEqual("Chris", app.username)
        self.assertEqual("Rossi", app.password)
        self.assertFalse(app.force_tls)
        self.assertTrue(app.no_tls)

        # Override nothing, make sure defaults come through
        f = open(ini_path, "w")
        f.write("[app:qp]\n\nqueue_path=foo\n")
        f.close()

        cmdline = """qp --config %s %s""" % (ini_path, self.dir)
        app = ConsoleApp(cmdline.split())
        self.assertEqual("qp", app.script_name)
        self.assertFalse(app._error)
        self.assertEqual(self.dir, app.queue_path)
        self.assertEqual("localhost", app.hostname)
        self.assertEqual(25, app.port)
        self.assertEqual(None, app.username)
        self.assertEqual(None, app.password)
        self.assertFalse(app.force_tls)
        self.assertFalse(app.no_tls)

    def test_delivery(self):
        from email.message import Message
        from_addr = "*****@*****.**"
        to_addr = "*****@*****.**"
        message = Message()
        message['Subject'] = 'Pants'
        message.set_payload('Nice pants, mister!')

        import transaction
        transaction.manager.begin()
        self.delivery.send(from_addr, to_addr, message)
        self.delivery.send(from_addr, to_addr, message)
        transaction.manager.commit()

        queued_messages = [m for m in self.maildir]
        self.assertEqual(2, len(queued_messages))
        self.assertEqual(0, len(self.mailer.sent_messages))

        cmdline = "qp %s" % self.queue_dir
        app = ConsoleApp(cmdline.split())
        app.mailer = self.mailer
        app.main()

        queued_messages = [m for m in self.maildir]
        self.assertEqual(0, len(queued_messages))
        self.assertEqual(2, len(self.mailer.sent_messages))
Example #16
0
class Mailer(object):
    """
    Manages sending of email messages.

    :param host: SMTP hostname
    :param port: SMTP port
    :param username: SMTP username
    :param password: SMPT password
    :param tls: use TLS
    :param ssl: use SSL
    :param keyfile: SSL key file 
    :param certfile: SSL certificate file
    :param queue_path: path to maildir for queued messages
    :param default_sender: default "from" address
    :param debug: SMTP debug level
    """
    def __init__(self,
                 host='localhost',
                 port=25,
                 username=None,
                 password=None,
                 tls=False,
                 ssl=False,
                 keyfile=None,
                 certfile=None,
                 queue_path=None,
                 default_sender=None,
                 debug=0):

        if ssl:

            self.smtp_mailer = SMTP_SSLMailer(hostname=host,
                                              port=port,
                                              username=username,
                                              password=password,
                                              no_tls=not (tls),
                                              force_tls=tls,
                                              debug_smtp=debug,
                                              keyfile=keyfile,
                                              certfile=certfile)

        else:

            self.smtp_mailer = SMTPMailer(hostname=host,
                                          port=port,
                                          username=username,
                                          password=password,
                                          no_tls=not (tls),
                                          force_tls=tls,
                                          debug_smtp=debug)

        self.direct_delivery = DirectMailDelivery(self.smtp_mailer)

        if queue_path:
            self.queue_delivery = QueuedMailDelivery(queue_path)
        else:
            self.queue_delivery = None

        self.default_sender = default_sender

    @classmethod
    def from_settings(cls, settings, prefix='mail.'):
        """
        Creates a new instance of **Message** from settings dict.

        :param settings: a settings dict-like
        :param prefix: prefix separating **pyramid_mailer** settings
        """

        settings = settings or {}

        kwarg_names = [
            prefix + k for k in ('host', 'port', 'username', 'password', 'tls',
                                 'ssl', 'keyfile', 'certfile', 'queue_path',
                                 'debug', 'default_sender')
        ]

        size = len(prefix)

        kwargs = dict(((k[size:], settings[k]) for k in settings.keys()
                       if k in kwarg_names))

        return cls(**kwargs)

    def send(self, message):
        """
        Sends a message. The message is handled inside a transaction, so 
        in case of failure (or the message fails) the message will not be sent.

        :param message: a **Message** instance.
        """

        return self.direct_delivery.send(*self._message_args(message))

    def send_immediately(self, message, fail_silently=False):
        """
        Sends a message immediately, outside the transaction manager. 

        If there is a connection error to the mail server this will have to 
        be handled manually. However if you pass ``fail_silently`` the error
        will be swallowed.

        :versionadded: 0.3

        :param message: a **Message** instance.

        :param fail_silently: silently handle connection errors.
        """

        try:
            return self.smtp_mailer.send(*self._message_args(message))
        except smtplib.socket.error:
            if not fail_silently:
                raise

    def send_to_queue(self, message):
        """
        Adds a message to a maildir queue.
        
        In order to handle this, the setting **mail.queue_path** must be 
        provided and must point to a valid maildir.

        :param message: a **Message** instance.
        """

        if not self.queue_delivery:
            raise RuntimeError, "No queue_path provided"

        return self.queue_delivery.send(*self._message_args(message))

    def _message_args(self, message):

        message.sender = message.sender or self.default_sender

        return (message.sender, message.send_to, message.to_message())
Example #17
0
 def bounce(self, mto, msg):
     QueuedMailDelivery.send(self, self.bounce_from, mto, msg)
Example #18
0
 def send(self, mto, msg):
     QueuedMailDelivery.send(self, self.mfrom, mto, msg)
Example #19
0
class Mailer(object):
    """Manages sending of email messages.

    :param host: SMTP hostname
    :param port: SMTP port
    :param username: SMTP username
    :param password: SMPT password
    :param tls: use TLS
    :param ssl: use SSL
    :param keyfile: SSL key file
    :param certfile: SSL certificate file
    :param queue_path: path to maildir for queued messages
    :param default_sender: default "from" address
    :param sendmail_app: path to "sendmail" binary.
           repoze defaults to "/usr/sbin/sendmail"
    :param sendmail_template: custom commandline template for sendmail binary,
           defaults to'["{sendmail_app}", "-t", "-i", "-f", "{sender}"]'
    :param transaction_manager: a transaction manager to join with when
           sending transactional emails
    :param debug: SMTP debug level
    """

    def __init__(self, **kw):
        smtp_mailer = kw.pop("smtp_mailer", None)
        if smtp_mailer is None:
            host = kw.pop("host", "localhost")
            port = kw.pop("port", 25)
            username = kw.pop("username", None)
            password = kw.pop("password", None)
            tls = kw.pop("tls", False)
            ssl = kw.pop("ssl", False)
            keyfile = kw.pop("keyfile", None)
            certfile = kw.pop("certfile", None)
            debug = kw.pop("debug", 0)
            if ssl:
                smtp_mailer = SMTP_SSLMailer(
                    hostname=host,
                    port=port,
                    username=username,
                    password=password,
                    no_tls=not (tls),
                    force_tls=tls,
                    debug_smtp=debug,
                    keyfile=keyfile,
                    certfile=certfile,
                )
            else:
                smtp_mailer = SMTPMailer(
                    hostname=host,
                    port=port,
                    username=username,
                    password=password,
                    no_tls=not (tls),
                    force_tls=tls,
                    debug_smtp=debug,
                )
        self.smtp_mailer = smtp_mailer

        sendmail_mailer = kw.pop("sendmail_mailer", None)
        if sendmail_mailer is None:
            sendmail_mailer = SendmailMailer(kw.pop("sendmail_app", None), kw.pop("sendmail_template", None))
        self.sendmail_mailer = sendmail_mailer

        self.queue_path = kw.pop("queue_path", None)
        self.default_sender = kw.pop("default_sender", None)

        transaction_manager = kw.pop("transaction_manager", None)
        if transaction_manager is None:
            transaction_manager = transaction.manager
        self.transaction_manager = transaction_manager

        if kw:
            raise ValueError("invalid options: %s" % ", ".join(sorted(kw.keys())))

        self.direct_delivery = DirectMailDelivery(self.smtp_mailer, transaction_manager=transaction_manager)

        if self.queue_path:
            self.queue_delivery = QueuedMailDelivery(self.queue_path, transaction_manager=transaction_manager)
        else:
            self.queue_delivery = None

        self.sendmail_delivery = DirectMailDelivery(self.sendmail_mailer, transaction_manager=transaction_manager)

    @classmethod
    def from_settings(cls, settings, prefix="mail."):
        """Create a new instance of 'Mailer' from settings dict.

        :param settings: a settings dict-like
        :param prefix: prefix separating 'pyramid_mailer' settings
        """
        settings = settings or {}

        kwarg_names = [
            prefix + k
            for k in (
                "host",
                "port",
                "username",
                "password",
                "tls",
                "ssl",
                "keyfile",
                "certfile",
                "queue_path",
                "debug",
                "default_sender",
                "sendmail_app",
                "sendmail_template",
            )
        ]

        size = len(prefix)

        kwargs = dict(((k[size:], settings[k]) for k in settings.keys() if k in kwarg_names))

        for key in ("tls", "ssl"):
            val = kwargs.get(key)
            if val:
                kwargs[key] = asbool(val)

        for key in ("debug", "port"):
            val = kwargs.get(key)
            if val:
                kwargs[key] = int(val)

        # list values
        for key in ("sendmail_template",):
            if key in kwargs:
                kwargs[key] = aslist(kwargs.get(key))

        username = kwargs.pop("username", None)
        password = kwargs.pop("password", None)
        if not (username or password):
            # Setting both username and password to the empty string,
            # causes repoze.sendmail.mailer.SMTPMailer to authenticate.
            # This most likely makes no sense, so, in that case
            # set username to None to skip authentication.
            username = password = None

        return cls(username=username, password=password, **kwargs)

    def bind(self, **kw):
        """Create a new mailer with the same server configuration but with
        different delivery options.

        :param default_sender: default "from" address
        :param transaction_manager: a transaction manager to join with when
            sending transactional emails

        """
        _check_bind_options(kw)
        default_sender = kw.get("default_sender", self.default_sender)
        transaction_manager = kw.get("transaction_manager", self.transaction_manager)

        return self.__class__(
            smtp_mailer=self.smtp_mailer,
            sendmail_mailer=self.sendmail_mailer,
            queue_path=self.queue_path,
            default_sender=default_sender,
            transaction_manager=transaction_manager,
        )

    def send(self, message):
        """Send a message.

        The message is handled inside a transaction, so in case of failure
        (or the message fails) the message will not be sent.

        :param message: a 'Message' instance.
        """
        return self.direct_delivery.send(*self._message_args(message))

    def send_immediately(self, message, fail_silently=False):
        """Send a message immediately, outside the transaction manager.

        If there is a connection error to the mail server this will have to
        be handled manually. However if you pass ``fail_silently`` the error
        will be swallowed.

        :versionadded: 0.3

        :param message: a 'Message' instance.

        :param fail_silently: silently handle connection errors.
        """
        try:
            return self.smtp_mailer.send(*self._message_args(message))
        except smtplib.socket.error:
            if not fail_silently:
                raise

    def send_to_queue(self, message):
        """Add a message to a maildir queue.

        In order to handle this, the setting 'mail.queue_path' must be
        provided and must point to a valid maildir.

        :param message: a 'Message' instance.
        """
        if not self.queue_delivery:
            raise RuntimeError("No queue_path provided")

        return self.queue_delivery.send(*self._message_args(message))

    def _message_args(self, message):

        message.sender = message.sender or self.default_sender
        # convert Lamson message to Python email package msessage
        msg = message.to_message()
        return (message.sender, message.send_to, msg)

    def send_sendmail(self, message):
        """Send a message within the transaction manager.

        Uses the local sendmail option

        :param message: a 'Message' instance.
        """
        return self.sendmail_delivery.send(*self._message_args(message))

    def send_immediately_sendmail(self, message, fail_silently=False):
        """Send a message immediately, outside the transaction manager.

        Uses the local sendmail option

        If there is a connection error to the mail server this will have to
        be handled manually. However if you pass ``fail_silently`` the error
        will be swallowed.

        :param message: a 'Message' instance.

        :param fail_silently: silently handle connection errors.
        """
        try:
            return self.sendmail_mailer.send(*self._message_args(message))
        except:
            if not fail_silently:
                raise
Example #20
0
class Mailer(object):
    """Manages sending of email messages.

    :param host: SMTP hostname
    :param port: SMTP port
    :param username: SMTP username
    :param password: SMPT password
    :param tls: use TLS
    :param ssl: use SSL
    :param keyfile: SSL key file
    :param certfile: SSL certificate file
    :param queue_path: path to maildir for queued messages
    :param default_sender: default "from" address
    :param sendmail_app: path to "sendmail" binary.
           repoze defaults to "/usr/sbin/sendmail"
    :param sendmail_template: custom commandline template for sendmail binary,
           defaults to'["{sendmail_app}", "-t", "-i", "-f", "{sender}"]'
    :param transaction_manager: a transaction manager to join with when
           sending transactional emails
    :param debug: SMTP debug level
    """
    def __init__(self, **kw):
        smtp_mailer = kw.pop('smtp_mailer', None)
        if smtp_mailer is None:
            host = kw.pop('host', 'localhost')
            port = kw.pop('port', 25)
            username = kw.pop('username', None)
            password = kw.pop('password', None)
            tls = kw.pop('tls', False)
            ssl = kw.pop('ssl', False)
            keyfile = kw.pop('keyfile', None)
            certfile = kw.pop('certfile', None)
            debug = kw.pop('debug', 0)
            if ssl:
                smtp_mailer = SMTP_SSLMailer(hostname=host,
                                             port=port,
                                             username=username,
                                             password=password,
                                             no_tls=not (tls),
                                             force_tls=tls,
                                             debug_smtp=debug,
                                             keyfile=keyfile,
                                             certfile=certfile)
            else:
                smtp_mailer = SMTPMailer(hostname=host,
                                         port=port,
                                         username=username,
                                         password=password,
                                         no_tls=not (tls),
                                         force_tls=tls,
                                         debug_smtp=debug)
        self.smtp_mailer = smtp_mailer

        sendmail_mailer = kw.pop('sendmail_mailer', None)
        if sendmail_mailer is None:
            sendmail_mailer = SendmailMailer(
                kw.pop('sendmail_app', None),
                kw.pop('sendmail_template', None),
            )
        self.sendmail_mailer = sendmail_mailer

        self.queue_path = kw.pop('queue_path', None)
        self.default_sender = kw.pop('default_sender', None)

        transaction_manager = kw.pop('transaction_manager', None)
        if transaction_manager is None:
            transaction_manager = transaction.manager
        self.transaction_manager = transaction_manager

        if kw:
            raise ValueError('invalid options: %s' %
                             ', '.join(sorted(kw.keys())))

        self.direct_delivery = DirectMailDelivery(
            self.smtp_mailer, transaction_manager=transaction_manager)

        if self.queue_path:
            self.queue_delivery = QueuedMailDelivery(
                self.queue_path, transaction_manager=transaction_manager)
        else:
            self.queue_delivery = None

        self.sendmail_delivery = DirectMailDelivery(
            self.sendmail_mailer, transaction_manager=transaction_manager)

    @classmethod
    def from_settings(cls, settings, prefix='mail.'):
        """Create a new instance of 'Mailer' from settings dict.

        :param settings: a settings dict-like
        :param prefix: prefix separating 'pyramid_mailer' settings
        """
        settings = settings or {}

        kwarg_names = [
            prefix + k
            for k in ('host', 'port', 'username', 'password', 'tls', 'ssl',
                      'keyfile', 'certfile', 'queue_path', 'debug',
                      'default_sender', 'sendmail_app', 'sendmail_template')
        ]

        size = len(prefix)

        kwargs = dict(((k[size:], settings[k]) for k in settings.keys()
                       if k in kwarg_names))

        for key in ('tls', 'ssl'):
            val = kwargs.get(key)
            if val:
                kwargs[key] = asbool(val)

        for key in ('debug', 'port'):
            val = kwargs.get(key)
            if val:
                kwargs[key] = int(val)

        # list values
        for key in ('sendmail_template', ):
            if key in kwargs:
                kwargs[key] = aslist(kwargs.get(key))

        username = kwargs.pop('username', None)
        password = kwargs.pop('password', None)
        if not (username or password):
            # Setting both username and password to the empty string,
            # causes repoze.sendmail.mailer.SMTPMailer to authenticate.
            # This most likely makes no sense, so, in that case
            # set username to None to skip authentication.
            username = password = None

        return cls(username=username, password=password, **kwargs)

    def bind(self, **kw):
        """Create a new mailer with the same server configuration but with
        different delivery options.

        :param default_sender: default "from" address
        :param transaction_manager: a transaction manager to join with when
            sending transactional emails

        """
        _check_bind_options(kw)
        default_sender = kw.get('default_sender', self.default_sender)
        transaction_manager = kw.get('transaction_manager',
                                     self.transaction_manager)

        return self.__class__(
            smtp_mailer=self.smtp_mailer,
            sendmail_mailer=self.sendmail_mailer,
            queue_path=self.queue_path,
            default_sender=default_sender,
            transaction_manager=transaction_manager,
        )

    def send(self, message):
        """Send a message.

        The message is handled inside a transaction, so in case of failure
        (or the message fails) the message will not be sent.

        :param message: a 'Message' instance.
        """
        return self.direct_delivery.send(*self._message_args(message))

    def send_immediately(self, message, fail_silently=False):
        """Send a message immediately, outside the transaction manager.

        If there is a connection error to the mail server this will have to
        be handled manually. However if you pass ``fail_silently`` the error
        will be swallowed.

        :versionadded: 0.3

        :param message: a 'Message' instance.

        :param fail_silently: silently handle connection errors.
        """
        try:
            return self.smtp_mailer.send(*self._message_args(message))
        except smtplib.socket.error:
            if not fail_silently:
                raise

    def send_to_queue(self, message):
        """Add a message to a maildir queue.

        In order to handle this, the setting 'mail.queue_path' must be
        provided and must point to a valid maildir.

        :param message: a 'Message' instance.
        """
        if not self.queue_delivery:
            raise RuntimeError("No queue_path provided")

        return self.queue_delivery.send(*self._message_args(message))

    def _message_args(self, message):

        message.sender = message.sender or self.default_sender
        # convert Lamson message to Python email package msessage
        msg = message.to_message()
        return (message.sender, message.send_to, msg)

    def send_sendmail(self, message):
        """Send a message within the transaction manager.

        Uses the local sendmail option

        :param message: a 'Message' instance.
        """
        return self.sendmail_delivery.send(*self._message_args(message))

    def send_immediately_sendmail(self, message, fail_silently=False):
        """Send a message immediately, outside the transaction manager.

        Uses the local sendmail option

        If there is a connection error to the mail server this will have to
        be handled manually. However if you pass ``fail_silently`` the error
        will be swallowed.

        :param message: a 'Message' instance.

        :param fail_silently: silently handle connection errors.
        """
        try:
            return self.sendmail_mailer.send(*self._message_args(message))
        except:
            if not fail_silently:
                raise
Example #21
0
class TestConsoleApp(TestCase):
    def setUp(self):
        from repoze.sendmail.delivery import QueuedMailDelivery
        from repoze.sendmail.maildir import Maildir
        self.dir = mkdtemp()
        self.queue_dir = os.path.join(self.dir, "queue")
        self.delivery = QueuedMailDelivery(self.queue_dir)
        self.maildir = Maildir(self.queue_dir, True)
        self.mailer = _makeMailerStub()

        self.save_stderr = sys.stderr
        sys.stderr = self.stderr = StringIO()

    def tearDown(self):
        sys.stderr = self.save_stderr
        shutil.rmtree(self.dir)

    def _captureLoggedErrors(self, cmdline):
        from repoze.sendmail import queue
        logged = []
        monkey = _Monkey(queue, _log_error=logged.append)
        # py 25 compat, can't use with statement
        exc_info = ()
        try:
            monkey.__enter__()
            app = ConsoleApp(cmdline.split())
        except: # pragma: no cover
            exc_info = sys.exc_info()
        monkey.__exit__(*exc_info)
        return app, logged

    def test_args_simple_ok(self):
        # Simplest case that works
        cmdline = "qp %s" % self.dir
        app = ConsoleApp(cmdline.split())
        self.assertEqual("qp", app.script_name)
        self.assertFalse(app._error)
        self.assertEqual(self.dir, app.queue_path)
        self.assertEqual("localhost", app.hostname)
        self.assertEqual(25, app.port)
        self.assertEqual(None, app.username)
        self.assertEqual(None, app.password)
        self.assertFalse(app.force_tls)
        self.assertFalse(app.no_tls)
        self.assertFalse(app.debug_smtp)

    def test_args_simple_error(self):
        # Simplest case that doesn't work
        cmdline = "qp"
        app, logged = self._captureLoggedErrors(cmdline)
        self.assertEqual("qp", app.script_name)
        self.assertTrue(app._error)
        self.assertEqual(None, app.queue_path)
        self.assertEqual("localhost", app.hostname)
        self.assertEqual(25, app.port)
        self.assertEqual(None, app.username)
        self.assertEqual(None, app.password)
        self.assertFalse(app.force_tls)
        self.assertFalse(app.no_tls)
        self.assertFalse(app.debug_smtp)
        self.assertEqual(len(logged), 1)
        app.main()

    def test_args_full_monty(self):
        # Use (almost) all of the options
        cmdline = """qp --hostname foo --port 75
                        --username chris --password rossi --force-tls
                        --debug-smtp --ssl
                        %s""" % self.dir
        app = ConsoleApp(cmdline.split())
        self.assertEqual("qp", app.script_name)
        self.assertFalse(app._error)
        self.assertEqual(self.dir, app.queue_path)
        self.assertEqual("foo", app.hostname)
        self.assertEqual(75, app.port)
        self.assertEqual("chris", app.username)
        self.assertEqual("rossi", app.password)
        self.assertTrue(app.force_tls)
        self.assertTrue(app.ssl)
        self.assertFalse(app.no_tls)
        self.assertTrue(app.debug_smtp)

    def test_args_username_no_password(self):
        # Test username without password
        cmdline = "qp --username chris %s" % self.dir
        app, logged = self._captureLoggedErrors(cmdline)
        self.assertTrue(app._error)
        self.assertEqual(len(logged), 1)

    def test_args_force_tls_no_tls(self):
        # Test force_tls and no_tls
        cmdline = "qp --force-tls --no-tls %s" % self.dir
        app, logged = self._captureLoggedErrors(cmdline)
        self.assertTrue(app._error)
        self.assertEqual(len(logged), 1)

    def test_args_hostname_no_hostname(self):
        cmdline = 'qp %s --hostname' % self.dir
        app, logged = self._captureLoggedErrors(cmdline)
        self.assertTrue(app._error)
        self.assertEqual(len(logged), 1)

    def test_args_port_no_port(self):
        cmdline = 'qp %s --port' % self.dir
        app, logged = self._captureLoggedErrors(cmdline)
        self.assertTrue(app._error)
        self.assertEqual(len(logged), 1)

    def test_args_bad_port(self):
        cmdline = 'qp %s --port foo' % self.dir
        app, logged = self._captureLoggedErrors(cmdline)
        self.assertTrue(app._error)
        self.assertEqual(len(logged), 1)

    def test_args_username_no_username(self):
        cmdline = 'qp %s --username' % self.dir
        app, logged = self._captureLoggedErrors(cmdline)
        self.assertTrue(app._error)
        self.assertEqual(len(logged), 1)

    def test_args_password_no_password(self):
        cmdline = 'qp %s --password' % self.dir
        app, logged = self._captureLoggedErrors(cmdline)
        self.assertTrue(app._error)
        self.assertEqual(len(logged), 1)

    def test_args_config_no_config(self):
        cmdline = 'qp %s --config' % self.dir
        app, logged = self._captureLoggedErrors(cmdline)
        self.assertTrue(app._error)
        self.assertEqual(len(logged), 1)

    def test_args_bad_arg(self):
        cmdline = 'qp --foo %s' % self.dir
        app, logged = self._captureLoggedErrors(cmdline)
        self.assertTrue(app._error)
        self.assertEqual(len(logged), 1)

    def test_args_too_many_queues(self):
        cmdline = 'qp %s foobar' % self.dir
        app, logged = self._captureLoggedErrors(cmdline)
        self.assertTrue(app._error)
        self.assertEqual(len(logged), 1)

    def test_ini_parse(self):
        ini_path = os.path.join(self.dir, "qp.ini")
        f = open(ini_path, "w")
        f.write(test_ini)
        f.close()

        # Override most everything
        cmdline = """qp --config %s""" % ini_path
        app = ConsoleApp(cmdline.split())
        self.assertEqual("qp", app.script_name)
        self.assertFalse(app._error)
        self.assertEqual("hammer/dont/hurt/em", app.queue_path)
        self.assertEqual("testhost", app.hostname)
        self.assertEqual(2525, app.port)
        self.assertEqual("Chris", app.username)
        self.assertEqual("Rossi", app.password)
        self.assertFalse(app.force_tls)
        self.assertTrue(app.no_tls)

        # Override nothing, make sure defaults come through
        f = open(ini_path, "w")
        f.write("[app:qp]\n\nqueue_path=foo\n")
        f.close()

        cmdline = """qp --config %s %s""" % (ini_path, self.dir)
        app = ConsoleApp(cmdline.split())
        self.assertEqual("qp", app.script_name)
        self.assertFalse(app._error)
        self.assertEqual(self.dir, app.queue_path)
        self.assertEqual("localhost", app.hostname)
        self.assertEqual(25, app.port)
        self.assertEqual(None, app.username)
        self.assertEqual(None, app.password)
        self.assertFalse(app.force_tls)
        self.assertFalse(app.no_tls)

    def test_delivery(self):
        from email.message import Message
        from_addr = "*****@*****.**"
        to_addr = "*****@*****.**"
        message = Message()
        message['Subject'] = 'Pants'
        message.set_payload('Nice pants, mister!')

        import transaction
        transaction.manager.begin()
        self.delivery.send(from_addr, to_addr, message)
        self.delivery.send(from_addr, to_addr, message)
        transaction.manager.commit()

        queued_messages = [m for m in self.maildir]
        self.assertEqual(2, len(queued_messages))
        self.assertEqual(0, len(self.mailer.sent_messages))

        cmdline = "qp %s" % self.queue_dir
        app = ConsoleApp(cmdline.split())
        app.mailer = self.mailer
        app.main()

        queued_messages = [m for m in self.maildir]
        self.assertEqual(0, len(queued_messages))
        self.assertEqual(2, len(self.mailer.sent_messages))