From dfb1c416880742881a6e8cfe1a3e5d729ef17afd Mon Sep 17 00:00:00 2001 From: mete0r Date: Thu, 1 Jan 2015 23:54:52 +0900 Subject: [PATCH] delivery --- mete0r_mailer/auth.py | 12 +++++----- mete0r_mailer/cli.py | 12 +++++----- mete0r_mailer/connector.py | 14 +++++------ mete0r_mailer/delivery.py | 48 ++++++++++++++++++++++++++++++++++++++ mete0r_mailer/mailer.py | 36 ++++++++++++++++++++++++++++ 5 files changed, 103 insertions(+), 19 deletions(-) create mode 100644 mete0r_mailer/delivery.py diff --git a/mete0r_mailer/auth.py b/mete0r_mailer/auth.py index a15d635..2651040 100644 --- a/mete0r_mailer/auth.py +++ b/mete0r_mailer/auth.py @@ -36,9 +36,9 @@ def authorizer_from_settings(settings, prefix): authorizer_type = settings.get(prefix + 'authorizer') logger.info('authorizer: %s', authorizer_type) if authorizer_type == 'XOAuth2GOAuthc': - return XOAuth2GOAuthc.from_settings(settings) + return XOAuth2GOAuthc.from_settings(settings, prefix + 'authorizer.') elif authorizer_type == 'XOAuth2Offline': - return XOAuth2Offline.from_settings(settings) + return XOAuth2Offline.from_settings(settings, prefix + 'authorizer.') raise ValueError(authorizer_type) @@ -48,8 +48,8 @@ def __init__(self, goauthc_path='goauthc'): self.goauthc_path = goauthc_path @classmethod - def from_settings(cls, settings): - goauthc_path = settings.get('xoauth2_goauthc.goauthc_path', + def from_settings(cls, settings, prefix='xoauth2_goauthc.'): + goauthc_path = settings.get(prefix + 'goauthc_path', 'goauthc') return cls(goauthc_path) @@ -75,8 +75,8 @@ def __init__(self, client_id, client_secret, accounts): } @classmethod - def from_settings(cls, settings): - path = settings.get('xoauth2_offline.credentials_path') + def from_settings(cls, settings, prefix='xoauth2_offline.'): + path = settings.get(prefix + 'credentials_path') with file(path) as f: d = json.load(f) return cls(client_id=d['client_id'], diff --git a/mete0r_mailer/cli.py b/mete0r_mailer/cli.py index 1538c06..1d090ab 100644 --- a/mete0r_mailer/cli.py +++ b/mete0r_mailer/cli.py @@ -29,6 +29,7 @@ from .connector import connector_from_settings from .mailer import SMTPLazyConnectMailer +from .delivery import delivery_from_settings logger = logging.getLogger(__name__) @@ -38,8 +39,8 @@ def qb(): logging.basicConfig(level=logging.INFO) with file(sys.argv[1]) as f: settings = json.load(f) - connector = connector_from_settings(settings, prefix='') - mailqueue = settings.get('mailqueue', 'Maildir') + connector = connector_from_settings(settings, prefix='qb.') + mailqueue = settings.get('qb.mailqueue', 'Maildir') with closing(SMTPLazyConnectMailer(connector)) as mailer: qp = QueueProcessor(mailer, mailqueue) qp.send_messages() @@ -49,15 +50,14 @@ def mail(): logging.basicConfig(level=logging.INFO) with file(sys.argv[1]) as f: settings = json.load(f) - mailqueue = settings.get('mailqueue', 'Maildir') + + delivery = delivery_from_settings(settings, 'mail.') import transaction transaction.manager.begin() try: - delivery = QueuedMailDelivery(mailqueue) - from_addr = sys.argv[2] - to_addrs = sys.argv[3:] + to_addrs = sys.argv[3:] or [from_addr] subject = raw_input('Subject: ') sys.stderr.write('Content:\n') content = sys.stdin.read() diff --git a/mete0r_mailer/connector.py b/mete0r_mailer/connector.py index 0fe66e5..3a22ac6 100644 --- a/mete0r_mailer/connector.py +++ b/mete0r_mailer/connector.py @@ -30,7 +30,7 @@ def connector_from_settings(settings, prefix): connector_type = settings.get(prefix + 'connector') logger.info('connector: %s', connector_type) if connector_type == 'XOAuth2Connector': - return XOAuth2Connector.from_settings(settings) + return XOAuth2Connector.from_settings(settings, prefix + 'connector.') raise ValueError(connector_type) @@ -48,12 +48,12 @@ def __init__(self, username, authorizer, self.debug_smtp = debug_smtp @classmethod - def from_settings(cls, settings): - username = settings.get('xoauth2_connector.username') - authorizer = authorizer_from_settings(settings, 'xoauth2_connector.') - hostname = settings.get('xoauth2_connector.hostname', 'smtp.gmail.com') - port = int(settings.get('xoauth2_connector.port', 587)) - timeout = int(settings.get('xoauth2_connector.timeout', 10)) + def from_settings(cls, settings, prefix='xoauth2_connector.'): + username = settings.get(prefix + 'username') + authorizer = authorizer_from_settings(settings, prefix) + hostname = settings.get(prefix + 'hostname', 'smtp.gmail.com') + port = int(settings.get(prefix + 'port', 587)) + timeout = int(settings.get(prefix + 'timeout', 10)) return cls(username=username, authorizer=authorizer, hostname=hostname, diff --git a/mete0r_mailer/delivery.py b/mete0r_mailer/delivery.py new file mode 100644 index 0000000..b3fd131 --- /dev/null +++ b/mete0r_mailer/delivery.py @@ -0,0 +1,48 @@ +# -*- coding: utf-8 -*- +# +# mete0r.mailer : mete0r's mailer +# Copyright (C) 2014 mete0r +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +import logging + +from repoze.sendmail.delivery import DirectMailDelivery +from repoze.sendmail.delivery import QueuedMailDelivery + +from .mailer import SMTPConnectMailer + + +logger = logging.getLogger(__name__) + + +def delivery_from_settings(settings, prefix): + delivery = settings.get(prefix + 'delivery') + if delivery == 'direct': + return direct_delivery_from_settings(settings, prefix + + 'delivery.direct.') + elif delivery == 'queued': + return queued_delivery_from_settings(settings, prefix + + 'delivery.queued.') + + +def direct_delivery_from_settings(settings, prefix=''): + mailer = SMTPConnectMailer.from_settings(settings, prefix + + 'mailer.') + return DirectMailDelivery(mailer) + + +def queued_delivery_from_settings(settings, prefix=''): + mailqueue_path = settings.get(prefix + 'mailqueue_path', 'Maildir') + return QueuedMailDelivery(mailqueue_path) diff --git a/mete0r_mailer/mailer.py b/mete0r_mailer/mailer.py index 26dd194..d83113c 100644 --- a/mete0r_mailer/mailer.py +++ b/mete0r_mailer/mailer.py @@ -16,6 +16,7 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . # +from contextlib import contextmanager from email.message import Message import logging @@ -24,6 +25,8 @@ from repoze.sendmail.interfaces import IMailer from repoze.sendmail._compat import SSLError +from .connector import connector_from_settings + logger = logging.getLogger(__name__) @@ -72,3 +75,36 @@ def send(self, fromaddr, toaddrs, message): def close(self): if self._connectionmailer: self._connectionmailer.close() + + +@implementer(IMailer) +class SMTPConnectMailer(object): + + def __init__(self, connector): + self.connector = connector + + @classmethod + def from_settings(cls, settings, prefix='smtp_connect_mailer.'): + connector = connector_from_settings(settings, prefix) + return cls(connector) + + def send(self, fromaddr, toaddrs, message): + with connect(self.connector) as connection: + connectionmailer = SMTPConnectionMailer(connection) + return connectionmailer.send(fromaddr, toaddrs, message) + + +@contextmanager +def connect(connector): + logger.info('Getting new connection...') + + connection = connector.connect() + try: + yield connection + finally: + logger.info('Closing connection...') + try: + connection.quit() + except SSLError: + # something weird happened while quiting + connection.close()