From 91e4481c450eb7eb928debc1cb7fa59bdb63dd7b Mon Sep 17 00:00:00 2001 From: Kali Kaneko Date: Tue, 25 Jul 2017 11:40:11 -0400 Subject: [pkg] packaging and path changes - move all the pixelated python package under src/ - move the pixelated_www package under the leap namespace - allow to set globally the static folder - add hours and minutes to the timestamp in package version, to allow for several releases a day. --- .../src/pixelated/adapter/services/mail_sender.py | 106 +++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 service/src/pixelated/adapter/services/mail_sender.py (limited to 'service/src/pixelated/adapter/services/mail_sender.py') diff --git a/service/src/pixelated/adapter/services/mail_sender.py b/service/src/pixelated/adapter/services/mail_sender.py new file mode 100644 index 00000000..063ea156 --- /dev/null +++ b/service/src/pixelated/adapter/services/mail_sender.py @@ -0,0 +1,106 @@ +# +# Copyright (c) 2014 ThoughtWorks, Inc. +# +# Pixelated 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. +# +# Pixelated 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 Pixelated. If not, see . +from StringIO import StringIO +from email.utils import parseaddr +from copy import deepcopy +from leap.bitmask.mail.outgoing.service import OutgoingMail + +from twisted.internet.defer import Deferred, fail +from twisted.mail.smtp import SMTPSenderFactory +from twisted.internet import reactor, defer +from pixelated.support.functional import flatten +from twisted.mail.smtp import User + +from twisted.logger import Logger + + +logger = Logger() + + +class SMTPDownException(Exception): + def __init__(self): + Exception.__init__(self, "Couldn't send mail now, try again later.") + + +NOT_NEEDED = None + + +class MailSenderException(Exception): + + def __init__(self, message, email_error_map): + super(MailSenderException, self).__init__(message, email_error_map) + self.email_error_map = email_error_map + + +class MailSender(object): + + def __init__(self, smtp_config, keymanager): + self._smtp_config = smtp_config + self._keymanager = keymanager + + @defer.inlineCallbacks + def sendmail(self, mail): + # message is changed in sending, but should be saved unaltered + mail = deepcopy(mail) + + recipients = flatten([mail.to, mail.cc, mail.bcc]) + + results = yield self._send_mail_to_all_recipients(mail, recipients) + all_succeeded = reduce(lambda a, b: a and b, [r[0] for r in results]) + + if not all_succeeded: + error_map = self._build_error_map(recipients, results) + raise MailSenderException('Failed to send mail to all recipients', error_map) + + defer.returnValue(all_succeeded) + + def _send_mail_to_all_recipients(self, mail, recipients): + outgoing_mail = self._create_outgoing_mail() + bccs = mail.bcc + deferreds = [] + + for recipient in recipients: + logger.info('_send_mail_to_all_recipients: Sending mail to recipient %s' % recipient) + self._define_bcc_field(mail, recipient, bccs) + smtp_recipient = self._create_twisted_smtp_recipient(recipient) + logger.info('_send_mail_to_all_recipients: Sending mail to smtp_recipient %s' % smtp_recipient) + deferreds.append(outgoing_mail.send_message(mail.to_smtp_format(), smtp_recipient)) + + return defer.DeferredList(deferreds, fireOnOneErrback=False, consumeErrors=True) + + def _define_bcc_field(self, mail, recipient, bccs): + if recipient in bccs: + mail.headers['Bcc'] = [recipient] + else: + mail.headers['Bcc'] = [] + + def _build_error_map(self, recipients, results): + error_map = {} + for email, error in [(recipients[idx], r[1]) for idx, r in enumerate(results)]: + error_map[email] = error + return error_map + + def _create_outgoing_mail(self): + return OutgoingMail(str(self._smtp_config.account_email), + self._keymanager, + self._smtp_config.cert_path, + self._smtp_config.cert_path, + str(self._smtp_config.remote_smtp_host), + int(self._smtp_config.remote_smtp_port)) + + def _create_twisted_smtp_recipient(self, recipient): + # TODO: Better is fix Twisted instead + return User(str(recipient), NOT_NEEDED, NOT_NEEDED, NOT_NEEDED) -- cgit v1.2.3