| 1 | #!/usr/bin/python |
|---|
| 2 | # -*- coding: UTF-8 -*- |
|---|
| 3 | # |
|---|
| 4 | # Copyright (c) 2007 Tarek Ziadé |
|---|
| 5 | # |
|---|
| 6 | # Authors: |
|---|
| 7 | # Tarek Ziadé <tarek@ziade.org> |
|---|
| 8 | # |
|---|
| 9 | # This program is free software; you can redistribute it and/or |
|---|
| 10 | # modify it under the terms of the GNU General Public License |
|---|
| 11 | # as published by the Free Software Foundation; either version 2 |
|---|
| 12 | # of the License, or (at your option) any later version. |
|---|
| 13 | # |
|---|
| 14 | # This program is distributed in the hope that it will be useful, |
|---|
| 15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 17 | # GNU General Public License for more details. |
|---|
| 18 | # |
|---|
| 19 | # You should have received a copy of the GNU General Public License |
|---|
| 20 | # along with this program; if not, write to the Free Software |
|---|
| 21 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
|---|
| 22 | from datetime import datetime |
|---|
| 23 | import os |
|---|
| 24 | import sys |
|---|
| 25 | import smtplib |
|---|
| 26 | import logging |
|---|
| 27 | from threading import Thread |
|---|
| 28 | import time |
|---|
| 29 | from base64 import b64decode |
|---|
| 30 | from email.MIMEText import MIMEText |
|---|
| 31 | |
|---|
| 32 | from model import mailed_data, mail_data |
|---|
| 33 | import settings |
|---|
| 34 | |
|---|
| 35 | class MailWorker(Thread): |
|---|
| 36 | """reads the SQLDB to do the jobs""" |
|---|
| 37 | |
|---|
| 38 | def __init__(self): |
|---|
| 39 | Thread.__init__(self) |
|---|
| 40 | self.is_working = False |
|---|
| 41 | self.running = False |
|---|
| 42 | |
|---|
| 43 | def _get_mails(self): |
|---|
| 44 | """returns lines of mail_data """ |
|---|
| 45 | return mail_data.select().execute().fetchall() |
|---|
| 46 | |
|---|
| 47 | def _get_message(self, mail): |
|---|
| 48 | """returns a Mime""" |
|---|
| 49 | data = b64decode(mail.data) |
|---|
| 50 | # some sgbd are in unicode |
|---|
| 51 | if isinstance(data, unicode): |
|---|
| 52 | data = data.decode('utf8') |
|---|
| 53 | msg = MIMEText(data) |
|---|
| 54 | msg['From'] = mail.sender |
|---|
| 55 | msg['To'] = mail.recipients |
|---|
| 56 | msg['Subject'] = mail.subject |
|---|
| 57 | msg.set_charset('utf-8') |
|---|
| 58 | msg['Date'] = mail.date.strftime('%c') |
|---|
| 59 | return msg |
|---|
| 60 | |
|---|
| 61 | def _send_mail(self, mail): |
|---|
| 62 | """sends the mail""" |
|---|
| 63 | server = smtplib.SMTP(settings.SMTP_SERVER) |
|---|
| 64 | msg = self._get_message(mail) |
|---|
| 65 | try: |
|---|
| 66 | server.sendmail(msg['From'], msg['To'], msg.as_string()) |
|---|
| 67 | finally: |
|---|
| 68 | server.quit() |
|---|
| 69 | logging.debug('mailer:message sent to %s' % msg['To']) |
|---|
| 70 | |
|---|
| 71 | def _store_mail(self, mail, error=None): |
|---|
| 72 | """stores the mail""" |
|---|
| 73 | if error is not None: |
|---|
| 74 | error = str(error) |
|---|
| 75 | ins = mailed_data.insert() |
|---|
| 76 | ins.execute(subject=mail.subject, sender=mail.sender, |
|---|
| 77 | original_id=mail.id, recipients=mail.recipients, |
|---|
| 78 | error=error, data=mail.data, date=datetime.now(), |
|---|
| 79 | status='processed') |
|---|
| 80 | |
|---|
| 81 | # removes from original table |
|---|
| 82 | mail_data.delete().execute(id=mail.id) |
|---|
| 83 | |
|---|
| 84 | def run(self): |
|---|
| 85 | """called threaded""" |
|---|
| 86 | self.running = True |
|---|
| 87 | logging.debug('mailer:launched') |
|---|
| 88 | |
|---|
| 89 | while self.running: |
|---|
| 90 | # index |
|---|
| 91 | self.is_working = True |
|---|
| 92 | try: |
|---|
| 93 | # get mails to send |
|---|
| 94 | mails = self._get_mails() |
|---|
| 95 | for mail in mails: |
|---|
| 96 | try: |
|---|
| 97 | # send then |
|---|
| 98 | self._send_mail(mail) |
|---|
| 99 | except Exception, e: |
|---|
| 100 | logging.debug('mailer:failed to send mail') |
|---|
| 101 | self._store_mail(mail, e) |
|---|
| 102 | else: |
|---|
| 103 | self._store_mail(mail) |
|---|
| 104 | finally: |
|---|
| 105 | self.is_working = False |
|---|
| 106 | time.sleep(.1) |
|---|
| 107 | |
|---|
| 108 | logging.debug('mailer:stopped') |
|---|
| 109 | |
|---|
| 110 | worker = None |
|---|
| 111 | |
|---|
| 112 | def start_server(): |
|---|
| 113 | """starts the worker""" |
|---|
| 114 | global worker |
|---|
| 115 | worker = MailWorker() |
|---|
| 116 | worker.start() |
|---|
| 117 | |
|---|
| 118 | def stop_server(): |
|---|
| 119 | """stops the worker""" |
|---|
| 120 | global worker |
|---|
| 121 | if worker is not None: |
|---|
| 122 | worker.running = False |
|---|
| 123 | worker.join() |
|---|
| 124 | worker = None |
|---|
| 125 | |
|---|
| 126 | def is_working(): |
|---|
| 127 | """tells if the worker works""" |
|---|
| 128 | return worker.is_working |
|---|
| 129 | |
|---|
| 130 | # will make sure the thread stops when the process quits |
|---|
| 131 | from atexit import register |
|---|
| 132 | register(stop_server) |
|---|