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)
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)
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)
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 bounce(self, mto, msg): QueuedMailDelivery.send(self, self.bounce_from, mto, msg)
def send(self, mto, msg): QueuedMailDelivery.send(self, self.mfrom, mto, msg)
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
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
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))
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())
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
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