117 lines
3.7 KiB
Python
117 lines
3.7 KiB
Python
# -*- coding: utf-8 -*-
|
|
from serpent.config import conf
|
|
from serpent import dataio, misc, rules
|
|
from datetime import datetime, timedelta
|
|
from os import path
|
|
from DNS import dnslookup
|
|
from operator import itemgetter
|
|
from smtplib import SMTP
|
|
|
|
class SmtpQueue(object):
|
|
def __init__(self, store, local_delivery):
|
|
self.stor = store
|
|
self.local_delivery = local_delivery
|
|
|
|
def add(self, data):
|
|
'''Ставит письмо в очередь'''
|
|
data['add_time'] = datetime.utcnow()
|
|
data['state'] = misc.MSG_ACTIVE
|
|
w = self.stor.write(data)
|
|
if not w:
|
|
return False
|
|
return self.__process_(data['id'])
|
|
|
|
def run(self):
|
|
'''Запускает обработку очереди'''
|
|
now = datetime.utcnow()
|
|
check_delta = timedelta(minutes = conf.smtp_queue_check_period)
|
|
expire_delta = timedelta(minutes = conf.smtp_queue_message_ttl)
|
|
for mid in self.__list_messages_():
|
|
info = self.stor.getinfo(mid)
|
|
if (now - info['add_time']) >= expire_delta:
|
|
self.stor.delete(mid)
|
|
continue
|
|
if (now - info['add_time']) >= check_delta:
|
|
continue
|
|
self.__process_(mid)
|
|
return True
|
|
|
|
def __local_deliver_(self, mid):
|
|
message = self.stor.read(mid)
|
|
user = rules.username_by_email(message['rcpt'])
|
|
return self.local_delivery.deliver(user, message['message'])
|
|
|
|
def __send_email_(self, mid):
|
|
info = self.stor.getinfo(mid)
|
|
try:
|
|
mail_servers = dnslookup(info['rcpt'][1], 'mx')
|
|
except:
|
|
return False
|
|
mail_servers = sorted(mail_servers, key=itemgetter(0))
|
|
for _, mx in mail_servers:
|
|
s = SMTP(local_hostname = conf.smtp_hostname)
|
|
try:
|
|
ret_code, banner = s.connect(mx, 25)
|
|
except:
|
|
s.quit()
|
|
continue
|
|
if ret_code != 220:
|
|
s.quit()
|
|
continue
|
|
try:
|
|
s.starttls()
|
|
except:
|
|
if conf.smtp_email_tls_required:
|
|
s.quit()
|
|
continue
|
|
from_addr = conf.smtp_email_delim.join(info['from'])
|
|
to_addr = conf.smtp_email_delim.join(info['rcpt'])
|
|
message = self.stor.read(mid)
|
|
try:
|
|
s.sendmail(from_addr, [to_addr], message['message'])
|
|
except:
|
|
s.quit()
|
|
continue
|
|
s.quit()
|
|
return True
|
|
return False
|
|
|
|
|
|
def __freeze_(self, mid):
|
|
info = self.stor.getinfo(mid)
|
|
if info:
|
|
if info['state'] != misc.MSG_FROZEN :
|
|
info['state'] = misc.MSG_FROZEN
|
|
if self.stor.setinfo(info):
|
|
return True
|
|
else:
|
|
return True
|
|
return False
|
|
|
|
def __process_(self, mid):
|
|
info = self.stor.getinfo(mid)
|
|
if info:
|
|
if info['rcpt'][1] in conf.local_domains:
|
|
if self.__local_deliver_(mid):
|
|
self.__remove_message_(mid)
|
|
return True
|
|
else:
|
|
return self.__freeze_(mid)
|
|
else:
|
|
if self.__send_email_(mid):
|
|
self.__remove_message_(mid)
|
|
return True
|
|
else:
|
|
return self.__freeze_(mid)
|
|
return False
|
|
|
|
def __list_messages_(self):
|
|
return self.stor.list()
|
|
|
|
def __remove_message_(self, mid):
|
|
self.stor.delete(mid)
|
|
|
|
mailstore = dataio.MailDirStore()
|
|
squeue = SmtpQueue(dataio.SmtpFileStore(path.join(conf.app_dir, conf.smtp_queue_dir)),
|
|
mailstore)
|