Ejemplo n.º 1
0
    def refuse(self, m, mylist, reason):
        deepdbg('Refuse mail for %s' % unicode(mylist))

        msgfrom = mylist.list_address_extended('owner')
        msgto = m['From']
        reason = u"\n\nYour message to the list %s has been refused\n\n" % unicode(mylist) + reason

        # create mail
        mail = MIMEMultipart()
        mail['Subject'] = u"Your message to the list %s has been refused " % unicode(mylist)
        mail['From'] = msgfrom
        mail['To'] = msgto
        mail.attach(MIMEText(reason, 'plain', 'utf8')) # error msg
        mail.attach(m) # previous mail

        # ugly hack we need to add headers at the TOP
#        items = m.items()
#        for key,val in items: m.__delitem__(key) # delete them all
#        for key,val in items: m.add_header(key,val) # re-add them all
#        mail.attach(m) # add original mail

        # send it
        try:
            connection = SMTPConnection() # we use the django one, configured with stuff from settings
            connection.open()
            if not connection.connection:
                raise SMTPException, "Fail to create SMTPConnection.connection"
            connection.connection.sendmail(
                mylist.list_address_extended('owner'),  # from, will be set in Return-Path
                [ msgto ],                              # to
                mail.as_string())                       # content
        except SMTPException, detail:
            err('refuse: SMTP Error while sending the email: %s'%detail)
            return # TODO : prevent loops if smtp fails : the mail stays in incoming and will be tried again in loop
Ejemplo n.º 2
0
def send_all(block_size=500):
    """
    Send all non-deferred messages in the queue.
    
    A lock file is used to ensure that this process can not be started again
    while it is already running.
    
    The ``block_size`` argument allows for queued messages to be iterated in
    blocks, allowing new prioritised messages to be inserted during iteration
    of a large number of queued messages.
    
    """
    lock = FileLock(LOCK_PATH)

    logger.debug("Acquiring lock...")
    try:
        # lockfile has a bug dealing with a negative LOCK_WAIT_TIMEOUT (which
        # is the default if it's not provided) systems which use a LinkFileLock
        # so ensure that it is never a negative number.
        lock.acquire(LOCK_WAIT_TIMEOUT and max(0, LOCK_WAIT_TIMEOUT))
    except AlreadyLocked:
        logger.debug("Lock already in place. Exiting.")
        return
    except LockTimeout:
        logger.debug("Waiting for the lock timed out. Exiting.")
        return
    logger.debug("Lock acquired.")

    start_time = time.time()

    sent = deferred = skipped = 0

    connection = None

    try:
        connection = SMTPConnection()
        blacklist = models.Blacklist.objects.values_list("email", flat=True)
        connection.open()
        for message in _message_queue(block_size):
            result = send_message(message, smtp_connection=connection, blacklist=blacklist)
            if result == constants.RESULT_SENT:
                sent += 1
            elif result == constants.RESULT_FAILED:
                deferred += 1
            elif result == constants.RESULT_SKIPPED:
                skipped += 1
        connection.close()
    finally:
        logger.debug("Releasing lock...")
        lock.release()
        logger.debug("Lock released.")

    logger.debug("")
    if sent or deferred or skipped:
        log = logger.warning
    else:
        log = logger.info
    log("%s sent, %s deferred, %s skipped." % (sent, deferred, skipped))
    logger.debug("Completed in %.2f seconds." % (time.time() - start_time))
Ejemplo n.º 3
0
 def forward_mail_to_subscribers(self, mail, subscribers, mylist):
     # actually forward it
     try:
         connection = SMTPConnection() # we use the django one, configured with stuff from settings
         connection.open()
         if not connection.connection:
             raise SMTPException, "Fail to create SMTPConnection.connection"
         connection.connection.sendmail(
             mylist.list_address_extended('owner'),  # from, will be set in Return-Path
             subscribers,                            # to
             mail.as_string())                       # content
     except SMTPException, detail:
         err('SMTP Error while sending the email: %s'%detail)
         return # TODO : prevent loops if smtp fails : the mail stays in incoming and will be tried again in loop
Ejemplo n.º 4
0
 def forward_mail_to_subscribers(self, mail, subscribers, mylist):
     # actually forward it
     try:
         connection = SMTPConnection(
         )  # we use the django one, configured with stuff from settings
         connection.open()
         if not connection.connection:
             raise SMTPException, "Fail to create SMTPConnection.connection"
         connection.connection.sendmail(
             mylist.list_address_extended(
                 'owner'),  # from, will be set in Return-Path
             subscribers,  # to
             mail.as_string())  # content
     except SMTPException, detail:
         err('SMTP Error while sending the email: %s' % detail)
         return  # TODO : prevent loops if smtp fails : the mail stays in incoming and will be tried again in loop
Ejemplo n.º 5
0
def send_message(queued_message, smtp_connection=None, blacklist=None,
                 log=True):
    """
    Send a queued message, returning a response code as to the action taken.
    
    The response codes can be found in ``django_mailer.constants``. The
    response will be either ``RESULT_SKIPPED`` for a blacklisted email,
    ``RESULT_FAILED`` for a deferred message or ``RESULT_SENT`` for a
    successful sent message.
    
    To allow optimizations if multiple messages are to be sent, an SMTP
    connection can be provided and a list of blacklisted email addresses.
    Otherwise an SMTP connection will be opened to send this message and the
    email recipient address checked against the ``Blacklist`` table.
    
    If the message recipient is blacklisted, the message will be removed from
    the queue without being sent. Otherwise, the message is attempted to be
    sent with an SMTP failure resulting in the message being flagged as
    deferred so it can be tried again later.
    
    By default, a log is created as to the action. Either way, the original
    message is not deleted.
    
    """
    message = queued_message.message
    if smtp_connection is None:
        smtp_connection = SMTPConnection()
    opened_connection = False

    if blacklist is None:
        blacklisted = models.Blacklist.objects.filter(email=message.to_address)
    else:
        blacklisted = message.to_address in blacklist

    log_message = ''
    if blacklisted:
        logger.info("Not sending to blacklisted email: %s" %
                     message.to_address.encode("utf-8"))
        queued_message.delete()
        result = constants.RESULT_SKIPPED
    else:
        try:
            logger.info("Sending message to %s: %s" %
                         (message.to_address.encode("utf-8"),
                          message.subject.encode("utf-8")))
            opened_connection = smtp_connection.open()
            smtp_connection.connection.sendmail(message.from_address,
                                                [message.to_address],
                                                message.encoded_message)
            queued_message.delete()
            result = constants.RESULT_SENT
        except (SocketError, smtplib.SMTPSenderRefused,
                smtplib.SMTPRecipientsRefused,
                smtplib.SMTPAuthenticationError), err:
            queued_message.defer()
            logger.warning("Message to %s deferred due to failure: %s" %
                            (message.to_address.encode("utf-8"), err))
            log_message = unicode(err)
            result = constants.RESULT_FAILED
Ejemplo n.º 6
0
    def refuse(self, m, mylist, reason):
        deepdbg('Refuse mail for %s' % unicode(mylist))

        msgfrom = mylist.list_address_extended('owner')
        msgto = m['From']
        reason = u"\n\nYour message to the list %s has been refused\n\n" % unicode(
            mylist) + reason

        # create mail
        mail = MIMEMultipart()
        mail[
            'Subject'] = u"Your message to the list %s has been refused " % unicode(
                mylist)
        mail['From'] = msgfrom
        mail['To'] = msgto
        mail.attach(MIMEText(reason, 'plain', 'utf8'))  # error msg
        mail.attach(m)  # previous mail

        # ugly hack we need to add headers at the TOP
        #        items = m.items()
        #        for key,val in items: m.__delitem__(key) # delete them all
        #        for key,val in items: m.add_header(key,val) # re-add them all
        #        mail.attach(m) # add original mail

        # send it
        try:
            connection = SMTPConnection(
            )  # we use the django one, configured with stuff from settings
            connection.open()
            if not connection.connection:
                raise SMTPException, "Fail to create SMTPConnection.connection"
            connection.connection.sendmail(
                mylist.list_address_extended(
                    'owner'),  # from, will be set in Return-Path
                [msgto],  # to
                mail.as_string())  # content
        except SMTPException, detail:
            err('refuse: SMTP Error while sending the email: %s' % detail)
            return  # TODO : prevent loops if smtp fails : the mail stays in incoming and will be tried again in loop
Ejemplo n.º 7
0
def send_invites():
    count = 0
    try:
        count = sys.argv[1]
    except:
        pass

    invites = Email_Invite.objects.filter(invited=False).order_by('created_date')[:count]
    
    messages = [ ]
    subject = 'Welcome to the Portrit preview!'
    html_content =  '<p>We are happy to announce the launch of the Portrit preview</p>' \
                    '<a href="http://portrit.com/">' \
                        '<img src="http://portrit.com/site_media/img/invite/invite.jpg"/>' \
                    '</a>' \
                    '<p>Please go to <a href="http://portrit.com">portrit.com</a> and login with the email address this message was sent to.</p>' \
                    '<p>With great power comes great responsibilty. With this in mind, we ask that you help us with any feedback you may have.<br>You can email us at <a href="mailto:[email protected]">[email protected]</a> or use the built in feedback control at the top of Portrit.</p>' \
                    '<br><br>' \
                    '<p style="color: #aeaeae; text-align: center; font-size: 12px;">You are receiving this email because you asked to receive an invite to portrit.com<br>' \
                    'Note: This email address is for distribution purposes only. Please do not reply to this email because your message will not be received.</p>'
    from_email = '*****@*****.**'
    from django.core.mail import SMTPConnection
    from django.core import mail
    connection = SMTPConnection()
    # Manually open the connection
    connection.open()
                              
    for invite in invites:
        email = mail.EmailMessage(subject, html_content, from_email,
                                    [invite.email], connection=connection)
        email.content_subtype = "html"
        messages.append(email)
        invite.invited = True
        invite.save()
    
    connection.send_messages(messages)
    connection.close()
Ejemplo n.º 8
0
 def handle_noargs(self, **options):
     current_site = Site.objects.get_current()
     # use low level SMTP object to improve performance
     smtp = SMTPConnection()
     smtp.open()
     notices_count = 0
     for user in User.objects.filter(email__isnull=False):
         notices = {}
         for notice in Notice.objects.notices_for(user).order_by('-notice_type__default', 'notice_type'):
             if should_send(user, notice.notice_type, DIGEST_MEDIUM):
                 if notice.notice_type.display in notices:
                     notices[notice.notice_type.display].append(notice)
                 else:
                     notices[notice.notice_type.display] = [notice]
                 notices_count += 1
                 notice.archive()
         if notices:
             context = Context({'notices': notices, 'user': user})
             body =  render_to_string ('notification/digest_email_body.html', context_instance=context)
             subject = render_to_string ('notification/digest_email_subject.txt', {'count': notices_count})
             msg = EmailMessage(subject, body, settings.DEFAULT_FROM_EMAIL, [user.email])
             msg.content_subtype = "html"  # Main content is now text/html
             smtp._send(msg)
     smtp.close()    
Ejemplo n.º 9
0
class SendingOutCommand(NoArgsCommand):
    subscriber_base = None # Subscriber.rsd or whatever
    from_email = 'The Daily Gazette <*****@*****.**>'
    WAIT_TIME = 60
    
    def set_content(self, dummy_request):
        raise NotImplemented
    
    def get_subject(self):
        today = datetime.date.today()
        return today.strftime("%%A, %%B %d, %%Y" % today.day)
    
    def get_sent_str(self):
        return datetime.date.today().strftime('%Y-%m-%d')
    
    def contents_for_subscriber(self, subscriber):
        return (self.text_content, self.html_content)
    
    
    def send_to_subscriber(self, subscriber):
        subj = self.subject
        frm = self.from_email
        text_content, html_content = self.contents_for_subscriber(subscriber)
        
        if subscriber.plain_text:
            msg = EmailMessage(subj, text_content, frm, [subscriber.email])
        else:
            msg = EmailMessage(subj, html_content, frm, [subscriber.email])
            msg.content_subtype = "html"

        # msg = EmailMessage(self.subject, text_content, self.from_email, [subscriber.email])
        # if not subscriber.plain_text:
        #     msg.multipart_subtype = 'alternative'
        #     msg.attach(content=html_content, mimetype='text/html')
        
        self.connection.send_messages([msg])
        
        # if it didn't just crash, sending was successful :)
        subscriber.last_sent = self.sent_str
        subscriber.save()
    
    def renew_connection(self, subscriber, retries=5, sleep_time_base=2):
        # close the old one
        self.connection.fail_silently = True
        self.connection.close()
        
        # get a new one
        for i in range(retries):
            try:
                self.connection = SMTPConnection()
                self.connection.open()
            except socket.timeout:
                self.add_error(subscriber, 'timeout while opening connection')
                time.sleep(sleep_time_base ** i)
            else:
                return
    
    def try_sending_to_subscriber(self, subscriber, repeat_index=0, max_repeats=2):
        if repeat_index >= max_repeats:
            return
        
        try:
            self.send_to_subscriber(subscriber)
        except smtplib.SMTPRecipientsRefused:
            self.add_error(subscriber, 'recipient refused')
        except smtplib.SMTPServerDisconnected:
            self.add_error(subscriber, 'server disconnected')
            self.renew_connection(subscriber)
            self.try_sending_to_subscriber(subscriber, repeat_index + 1, max_repeats)
        except socket.sslerror:
            self.add_error(subscriber, 'ssl error') # probably timeout
            self.renew_connection(subscriber)
            self.try_sending_to_subscriber(subscriber, repeat_index + 1, max_repeats)
        except socket.timeout:
            self.add_error(subscriber, 'timeout')
            self.renew_connection(subscriber)
            self.try_sending_to_subscriber(subscriber, repeat_index + 1, max_repeats)
        except smtplib.SMTPException:
            self.add_error(subscriber, 'smtp error')
        except Exception:
            self.add_error(subscriber, 'generic error')
    
    def add_error(self, subscriber, key):
        self.errors.setdefault(subscriber.email, {})
        self.errors[subscriber.email].setdefault(key, [])
        exc_type, exc_val, exc_trace = sys.exc_info()
        self.errors[subscriber.email][key].append({
            'type': exc_type,
            'val': exc_val,
            'traceback': ''.join(traceback.format_exception(exc_type, exc_val, exc_trace)),
            'time': datetime.datetime.now()
        })
    
    
    def handle_noargs(self, **options):
        dummy_request = HttpRequest()
        dummy_request.GET['for_email'] = 'true'
        self.set_content(dummy_request)
        
        self.subject = self.get_subject()
        self.sent_str = self.get_sent_str()
        
        self.connection = SMTPConnection()
        self.errors = {}
        
        print 'starting: ' + datetime.datetime.now().strftime("%c")
        
        # try up to four times, if necessary
        for i in range(4):
            not_sent = self.subscriber_base.exclude(last_sent=self.sent_str)
            if len(not_sent): # intentionally resolve the query
                if i != 0:
                    print datetime.datetime.now().strftime('%c'), 
                    print '- sleeping before retrying %s emails...' % len(not_sent)
                    time.sleep(self.WAIT_TIME)
                for subscriber in not_sent:
                    self.try_sending_to_subscriber(subscriber)
        
        # any that *still* didn't work?
        error_output = []
        for sub in self.subscriber_base.exclude(last_sent=self.sent_str):
            errors = [ '%d %s' % (len(data), kind) for kind, data 
                       in self.errors[sub.email].items() ]
            error_output.append('errors with %s: %s' % (sub.email, '\t'.join(errors)))
        
        if error_output:
            print '\n', '\n'.join(error_output), '\n'
            mail_admins('Errors sending out',
                "Got the following errors while sending the email:\n" +
                '\n'.join(error_output) +
                '\n\nMore information is available by loading the pickled log file.'
            )
        
        if self.errors:
            print 'more info available in the pickle file'
        pickle.dump(self.errors, sys.stderr)
        
        print 'finished: ' + datetime.datetime.now().strftime("%c")
Ejemplo n.º 10
0
class SendingOutCommand(NoArgsCommand):
    subscriber_base = None  # Subscriber.rsd or whatever
    from_email = 'The Daily Gazette <*****@*****.**>'
    WAIT_TIME = 60

    def set_content(self, dummy_request):
        raise NotImplemented

    def get_subject(self):
        today = datetime.date.today()
        return today.strftime("%%A, %%B %d, %%Y" % today.day)

    def get_sent_str(self):
        return datetime.date.today().strftime('%Y-%m-%d')

    def contents_for_subscriber(self, subscriber):
        return (self.text_content, self.html_content)

    def send_to_subscriber(self, subscriber):
        subj = self.subject
        frm = self.from_email
        text_content, html_content = self.contents_for_subscriber(subscriber)

        if subscriber.plain_text:
            msg = EmailMessage(subj, text_content, frm, [subscriber.email])
        else:
            msg = EmailMessage(subj, html_content, frm, [subscriber.email])
            msg.content_subtype = "html"

        # msg = EmailMessage(self.subject, text_content, self.from_email, [subscriber.email])
        # if not subscriber.plain_text:
        #     msg.multipart_subtype = 'alternative'
        #     msg.attach(content=html_content, mimetype='text/html')

        self.connection.send_messages([msg])

        # if it didn't just crash, sending was successful :)
        subscriber.last_sent = self.sent_str
        subscriber.save()

    def renew_connection(self, subscriber, retries=5, sleep_time_base=2):
        # close the old one
        self.connection.fail_silently = True
        self.connection.close()

        # get a new one
        for i in range(retries):
            try:
                self.connection = SMTPConnection()
                self.connection.open()
            except socket.timeout:
                self.add_error(subscriber, 'timeout while opening connection')
                time.sleep(sleep_time_base**i)
            else:
                return

    def try_sending_to_subscriber(self,
                                  subscriber,
                                  repeat_index=0,
                                  max_repeats=2):
        if repeat_index >= max_repeats:
            return

        try:
            self.send_to_subscriber(subscriber)
        except smtplib.SMTPRecipientsRefused:
            self.add_error(subscriber, 'recipient refused')
        except smtplib.SMTPServerDisconnected:
            self.add_error(subscriber, 'server disconnected')
            self.renew_connection(subscriber)
            self.try_sending_to_subscriber(subscriber, repeat_index + 1,
                                           max_repeats)
        except socket.sslerror:
            self.add_error(subscriber, 'ssl error')  # probably timeout
            self.renew_connection(subscriber)
            self.try_sending_to_subscriber(subscriber, repeat_index + 1,
                                           max_repeats)
        except socket.timeout:
            self.add_error(subscriber, 'timeout')
            self.renew_connection(subscriber)
            self.try_sending_to_subscriber(subscriber, repeat_index + 1,
                                           max_repeats)
        except smtplib.SMTPException:
            self.add_error(subscriber, 'smtp error')
        except Exception:
            self.add_error(subscriber, 'generic error')

    def add_error(self, subscriber, key):
        self.errors.setdefault(subscriber.email, {})
        self.errors[subscriber.email].setdefault(key, [])
        exc_type, exc_val, exc_trace = sys.exc_info()
        self.errors[subscriber.email][key].append({
            'type':
            exc_type,
            'val':
            exc_val,
            'traceback':
            ''.join(traceback.format_exception(exc_type, exc_val, exc_trace)),
            'time':
            datetime.datetime.now()
        })

    def handle_noargs(self, **options):
        dummy_request = HttpRequest()
        dummy_request.GET['for_email'] = 'true'
        self.set_content(dummy_request)

        self.subject = self.get_subject()
        self.sent_str = self.get_sent_str()

        self.connection = SMTPConnection()
        self.errors = {}

        print 'starting: ' + datetime.datetime.now().strftime("%c")

        # try up to four times, if necessary
        for i in range(4):
            not_sent = self.subscriber_base.exclude(last_sent=self.sent_str)
            if len(not_sent):  # intentionally resolve the query
                if i != 0:
                    print datetime.datetime.now().strftime('%c'),
                    print '- sleeping before retrying %s emails...' % len(
                        not_sent)
                    time.sleep(self.WAIT_TIME)
                for subscriber in not_sent:
                    self.try_sending_to_subscriber(subscriber)

        # any that *still* didn't work?
        error_output = []
        for sub in self.subscriber_base.exclude(last_sent=self.sent_str):
            errors = [
                '%d %s' % (len(data), kind)
                for kind, data in self.errors[sub.email].items()
            ]
            error_output.append('errors with %s: %s' %
                                (sub.email, '\t'.join(errors)))

        if error_output:
            print '\n', '\n'.join(error_output), '\n'
            mail_admins(
                'Errors sending out',
                "Got the following errors while sending the email:\n" +
                '\n'.join(error_output) +
                '\n\nMore information is available by loading the pickled log file.'
            )

        if self.errors:
            print 'more info available in the pickle file'
        pickle.dump(self.errors, sys.stderr)

        print 'finished: ' + datetime.datetime.now().strftime("%c")