2019-01-29 00:11:12 +01:00
#!/usr/bin/python
import smtplib
import os
import mysql . connector
from email . MIMEMultipart import MIMEMultipart
from email . MIMEText import MIMEText
from email . Utils import COMMASPACE , formatdate
import cgi
import jinja2
from jinja2 import Template
import json
import redis
import time
2019-02-05 10:38:28 +01:00
import html2text
2019-02-06 09:21:54 +01:00
import socket
2019-01-29 00:11:12 +01:00
while True :
try :
r = redis . StrictRedis ( host = ' redis ' , decode_responses = True , port = 6379 , db = 0 )
r . ping ( )
except Exception as ex :
print ' %s - trying again... ' % ( ex )
time . sleep ( 3 )
else :
break
time_now = int ( time . time ( ) )
def query_mysql ( query , headers = True , update = False ) :
while True :
try :
2019-02-06 09:21:54 +01:00
cnx = mysql . connector . connect ( unix_socket = ' /var/run/mysqld/mysqld.sock ' , user = ' mailcow ' , passwd = ' 9S6jd31ijEytZE9lQ8sWOxK34tg5 ' , database = ' mailcow ' , charset = " utf8 " )
2019-01-29 00:11:12 +01:00
except Exception as ex :
print ' %s - trying again... ' % ( ex )
time . sleep ( 3 )
else :
break
cur = cnx . cursor ( )
cur . execute ( query )
if not update :
result = [ ]
columns = tuple ( [ d [ 0 ] . decode ( ' utf8 ' ) for d in cur . description ] )
for row in cur :
2019-01-31 20:53:08 +01:00
if headers :
2019-01-29 00:11:12 +01:00
result . append ( dict ( zip ( columns , row ) ) )
else :
result . append ( row )
cur . close ( )
cnx . close ( )
return result
else :
cnx . commit ( )
cur . close ( )
cnx . close ( )
2019-02-06 09:21:54 +01:00
def notify_rcpt ( rcpt , msg_count , quarantine_acl ) :
meta_query = query_mysql ( ' SELECT SHA2(CONCAT(id, qid), 256) AS qhash, id, subject, score, sender, created FROM quarantine WHERE notified = 0 AND rcpt = " %s " ' % ( rcpt ) )
2019-01-29 00:11:12 +01:00
if r . get ( ' Q_HTML ' ) :
try :
template = Template ( r . get ( ' Q_HTML ' ) )
except :
print " Error: Cannot parse quarantine template, falling back to default template. "
2019-01-31 22:18:32 +01:00
with open ( ' /templates/quarantine.tpl ' ) as file_ :
template = Template ( file_ . read ( ) )
2019-01-29 00:11:12 +01:00
else :
with open ( ' /templates/quarantine.tpl ' ) as file_ :
template = Template ( file_ . read ( ) )
2019-02-06 09:21:54 +01:00
html = template . render ( meta = meta_query , counter = msg_count , hostname = socket . gethostname ( ) , quarantine_acl = quarantine_acl )
2019-02-05 10:38:28 +01:00
text = html2text . html2text ( html )
2019-01-29 00:11:12 +01:00
count = 0
while count < 15 :
try :
2019-01-31 22:18:32 +01:00
server = smtplib . SMTP ( ' postfix ' , 590 , ' quarantine ' )
2019-01-29 00:11:12 +01:00
server . ehlo ( )
msg = MIMEMultipart ( ' alternative ' )
msg [ ' From ' ] = r . get ( ' Q_SENDER ' ) or " quarantine@localhost "
msg [ ' Subject ' ] = r . get ( ' Q_SUBJ ' ) or " Spam Quarantine Notification "
msg [ ' Date ' ] = formatdate ( localtime = True )
2019-01-31 21:45:58 +01:00
text_part = MIMEText ( text , ' plain ' , ' utf-8 ' )
html_part = MIMEText ( html , ' html ' , ' utf-8 ' )
2019-01-29 00:11:12 +01:00
msg . attach ( text_part )
msg . attach ( html_part )
msg [ ' To ' ] = str ( rcpt )
text = msg . as_string ( )
server . sendmail ( msg [ ' From ' ] , msg [ ' To ' ] , text )
server . quit ( )
for res in meta_query :
query_mysql ( ' UPDATE quarantine SET notified = 1 WHERE id = " %d " ' % ( res [ ' id ' ] ) , update = True )
r . hset ( ' Q_LAST_NOTIFIED ' , record [ ' rcpt ' ] , time_now )
break
except Exception as ex :
print ' %s ' % ( ex )
time . sleep ( 3 )
2019-02-06 09:21:54 +01:00
records = query_mysql ( ' SELECT IFNULL(user_acl.quarantine, 0) AS quarantine_acl, count(id) AS counter, rcpt FROM quarantine LEFT OUTER JOIN user_acl ON user_acl.username = rcpt WHERE notified = 0 AND rcpt in (SELECT username FROM mailbox) GROUP BY rcpt ' )
2019-01-29 00:11:12 +01:00
for record in records :
2019-02-05 00:00:22 +01:00
attrs = ' '
attrs_json = ' '
try :
last_notification = int ( r . hget ( ' Q_LAST_NOTIFIED ' , record [ ' rcpt ' ] ) )
if last_notification > time_now :
print ' Last notification is > time now, assuming never '
last_notification = 0
except Exception as ex :
print ' Could not determine last notification for %s , assuming never ' % ( record [ ' rcpt ' ] )
last_notification = 0
2019-01-29 00:11:12 +01:00
attrs_json = query_mysql ( ' SELECT attributes FROM mailbox WHERE username = " %s " ' % ( record [ ' rcpt ' ] ) )
attrs = json . loads ( str ( attrs_json [ 0 ] [ ' attributes ' ] ) )
2019-02-05 00:00:22 +01:00
if attrs [ ' quarantine_notification ' ] not in ( ' hourly ' , ' daily ' , ' weekly ' , ' never ' ) :
print ' Abnormal quarantine_notification value '
continue
2019-01-29 00:11:12 +01:00
if attrs [ ' quarantine_notification ' ] == ' hourly ' :
2019-01-29 12:13:26 +01:00
if last_notification == 0 or ( last_notification + 3600 ) < time_now :
print " Notifying %s about %d new items in quarantine " % ( record [ ' rcpt ' ] , record [ ' counter ' ] )
2019-02-06 09:21:54 +01:00
notify_rcpt ( record [ ' rcpt ' ] , record [ ' counter ' ] , record [ ' quarantine_acl ' ] )
2019-01-29 00:11:12 +01:00
elif attrs [ ' quarantine_notification ' ] == ' daily ' :
2019-01-29 12:13:26 +01:00
if last_notification == 0 or ( last_notification + 86400 ) < time_now :
print " Notifying %s about %d new items in quarantine " % ( record [ ' rcpt ' ] , record [ ' counter ' ] )
2019-02-06 09:21:54 +01:00
notify_rcpt ( record [ ' rcpt ' ] , record [ ' counter ' ] , record [ ' quarantine_acl ' ] )
2019-01-29 00:11:12 +01:00
elif attrs [ ' quarantine_notification ' ] == ' weekly ' :
2019-01-29 12:13:26 +01:00
if last_notification == 0 or ( last_notification + 604800 ) < time_now :
print " Notifying %s about %d new items in quarantine " % ( record [ ' rcpt ' ] , record [ ' counter ' ] )
2019-02-06 09:21:54 +01:00
notify_rcpt ( record [ ' rcpt ' ] , record [ ' counter ' ] , record [ ' quarantine_acl ' ] )
2019-01-29 00:11:12 +01:00
else :
break