mirror of
https://github.com/chillout2k/gulag.git
synced 2025-12-13 16:00:18 +00:00
RSPAMD HTTP2IMAP relay
This commit is contained in:
parent
71d6b0b200
commit
05939e8732
72
app/Gulag.py
72
app/Gulag.py
@ -35,9 +35,9 @@ class Gulag:
|
|||||||
except GulagDBException as e:
|
except GulagDBException as e:
|
||||||
raise GulagException(e.message) from e
|
raise GulagException(e.message) from e
|
||||||
|
|
||||||
|
# Iterate through all mailboxes, extract metadata
|
||||||
|
# from all unseen mails and import them into database
|
||||||
def import_quarmails(self):
|
def import_quarmails(self):
|
||||||
# Alle Mailboxes durchiterieren und die Meta-Infos aller neuen (unseen)
|
|
||||||
# Nachrichten in die Datenbank importieren
|
|
||||||
for mailbox in self.db.get_mailboxes():
|
for mailbox in self.db.get_mailboxes():
|
||||||
imap_mb = None
|
imap_mb = None
|
||||||
try:
|
try:
|
||||||
@ -81,14 +81,21 @@ class Gulag:
|
|||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
x_spam_status = email.header.decode_header(msg['X-Spam-Status'])[0][0]
|
x_spam_status = email.header.decode_header(msg['X-Spam-Status'])[0][0]
|
||||||
|
mx_queue_id = "n.a."
|
||||||
|
try:
|
||||||
|
mx_queue_id = email.header.decode_header(msg['X-Spam-QID'])[0][0]
|
||||||
|
except:
|
||||||
|
pass
|
||||||
r5321_rcpts = str(r5321_rcpts).lower()
|
r5321_rcpts = str(r5321_rcpts).lower()
|
||||||
r5321_rcpts = r5321_rcpts.replace(" ", "")
|
r5321_rcpts = r5321_rcpts.replace(" ", "")
|
||||||
|
r5321_rcpts = r5321_rcpts.replace("<", "")
|
||||||
|
r5321_rcpts = r5321_rcpts.replace(">", "")
|
||||||
# Pro Envelope-RCPT einen Eintrag in die DB schreiben.
|
# Pro Envelope-RCPT einen Eintrag in die DB schreiben.
|
||||||
# Die E-Mail im IMAP-Backend existiert jedoch nur ein Mal und wird
|
# Die E-Mail im IMAP-Backend existiert jedoch nur ein Mal und wird
|
||||||
# über die mailbox_id sowie die imap_uid mehrfach referenziert.
|
# über die mailbox_id sowie die imap_uid mehrfach referenziert.
|
||||||
for r5321_rcpt in r5321_rcpts.split(","):
|
for r5321_rcpt in r5321_rcpts.split(","):
|
||||||
quarmail_id = self.db.add_quarmail({
|
quarmail_id = self.db.add_quarmail({
|
||||||
'mx_queue_id': 'queue_id', 'env_from': r5321_from, 'env_rcpt': r5321_rcpt,
|
'mx_queue_id': mx_queue_id, 'env_from': r5321_from, 'env_rcpt': r5321_rcpt,
|
||||||
'hdr_cf': x_spam_status, 'hdr_from': r5322_from, 'hdr_subject': subject,
|
'hdr_cf': x_spam_status, 'hdr_from': r5322_from, 'hdr_subject': subject,
|
||||||
'hdr_msgid': msg_id, 'hdr_date': date, 'cf_meta': 'cf_meta',
|
'hdr_msgid': msg_id, 'hdr_date': date, 'cf_meta': 'cf_meta',
|
||||||
'mailbox_id': 'quarantine@zwackl.de', 'imap_uid': uid, 'msg_size': msg_size
|
'mailbox_id': 'quarantine@zwackl.de', 'imap_uid': uid, 'msg_size': msg_size
|
||||||
@ -142,7 +149,7 @@ class Gulag:
|
|||||||
except GulagDBException as e:
|
except GulagDBException as e:
|
||||||
raise GulagException("GulagDBException: " + e.message) from e
|
raise GulagException("GulagDBException: " + e.message) from e
|
||||||
|
|
||||||
def rspamd_http2smtp(self,mailbox_id):
|
def rspamd_http2imap(self,mailbox_id):
|
||||||
mailbox = None
|
mailbox = None
|
||||||
try:
|
try:
|
||||||
mailbox = self.db.get_mailbox(mailbox_id)
|
mailbox = self.db.get_mailbox(mailbox_id)
|
||||||
@ -151,31 +158,50 @@ class Gulag:
|
|||||||
|
|
||||||
if(request.headers.get('X-Rspamd-From') == None):
|
if(request.headers.get('X-Rspamd-From') == None):
|
||||||
raise GulagException("Missing Rspamd-specific headers (e.g. X-Rspamd-From)!")
|
raise GulagException("Missing Rspamd-specific headers (e.g. X-Rspamd-From)!")
|
||||||
|
|
||||||
# recompose rejected mail that will be sent to quarantine mailbox
|
# recompose rejected mail that will be sent to quarantine mailbox
|
||||||
#FIXME: print("mx_queue_id: " + request.headers.get('X-Rspamd-Qid'))
|
|
||||||
msg = None
|
msg = None
|
||||||
try:
|
try:
|
||||||
msg = email.message_from_string(request.get_data(as_text=True))
|
rcpts_hdr = ""
|
||||||
rcpts_hdr = str(request.headers.get('X-Rspamd-Rcpt'))
|
for rcpt in json.loads(str(request.headers.get('X-Rspamd-Rcpt'))):
|
||||||
# FIXME: special chars []" rausstrippen! -> JSON!!!
|
if(len(rcpts_hdr) > 0):
|
||||||
print("RCPTs neu: " + rcpts_hdr)
|
rcpts_hdr = rcpts_hdr + "," + rcpt
|
||||||
msg.add_header("X-Envelope-To-Blocked", rcpts_hdr)
|
else:
|
||||||
msg.add_header("X-Spam-Status", request.headers.get('X-Rspamd-Symbols'))
|
rcpts_hdr = rcpt
|
||||||
# except email.errors.* as e:
|
msg = "Return-Path: <" + request.headers.get('X-Rspamd-From') + ">\r\n"
|
||||||
|
msg = msg + "Received: from rspamd_http2imap relay by gulag-mailbox " + mailbox_id + "\r\n"
|
||||||
|
msg = msg + "X-Envelope-To-Blocked: " + rcpts_hdr + "\r\n"
|
||||||
|
msg = msg + "X-Spam-Status: " + request.headers.get('X-Rspamd-Symbols') + "\r\n"
|
||||||
|
msg = msg + "X-Spam-QID: " + request.headers.get('X-Rspamd-Qid') + "\r\n"
|
||||||
|
msg = msg + request.get_data(as_text=True)
|
||||||
|
#FIXME: except email.errors.* as e:
|
||||||
except:
|
except:
|
||||||
raise GulagException(str(sys.exc_info()))
|
raise GulagException(str(sys.exc_info()))
|
||||||
|
|
||||||
|
# Use IMAP´s APPEND command to store the message into mailbox
|
||||||
|
imap_mb = None
|
||||||
try:
|
try:
|
||||||
with SMTP(host=mailbox['smtp_server'],port=mailbox['smtp_port']) as smtp:
|
imap_mb = IMAPmailbox(
|
||||||
try:
|
mailbox['imap_server'],
|
||||||
smtp.sendmail(
|
mailbox['imap_user'],
|
||||||
request.headers.get('X-Rspamd-From'),
|
mailbox['imap_pass'],
|
||||||
mailbox_id,
|
mailbox['imap_mailbox']
|
||||||
msg.as_string()
|
|
||||||
)
|
)
|
||||||
except (SMTPRecipientsRefused,SMTPHeloError,SMTPSenderRefused,SMTPDataError) as e:
|
imap_mb.append_message(msg)
|
||||||
raise GulagException(str(e)) from e
|
except IMAPmailboxException as e:
|
||||||
except TimeoutError as e:
|
raise GulagException(e.message) from e
|
||||||
raise GulagException(str(e)) from e
|
# try:
|
||||||
|
# if not mailbox['smtp_server']:
|
||||||
|
# raise GulagException("No SMTP server configured for mailbox " + mailbox_id)
|
||||||
|
# # FIXME: SMTP tranaport security and authentication!
|
||||||
|
# with SMTP(host=mailbox['smtp_server'],port=mailbox['smtp_port']) as smtp:
|
||||||
|
# try:
|
||||||
|
# smtp.sendmail(
|
||||||
|
# request.headers.get('X-Rspamd-From'),
|
||||||
|
# mailbox_id,
|
||||||
|
# msg
|
||||||
|
# )
|
||||||
|
# except (SMTPRecipientsRefused,SMTPHeloError,SMTPSenderRefused,SMTPDataError) as e:
|
||||||
|
# raise GulagException(str(e)) from e
|
||||||
|
# except TimeoutError as e:
|
||||||
|
# raise GulagException(str(e)) from e
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import imaplib
|
import imaplib
|
||||||
import email
|
import email
|
||||||
import email.header
|
import email.header
|
||||||
|
import time
|
||||||
|
|
||||||
class IMAPmailboxException(Exception):
|
class IMAPmailboxException(Exception):
|
||||||
message = None
|
message = None
|
||||||
@ -71,19 +72,29 @@ class IMAPmailbox:
|
|||||||
msg = email.message_from_bytes(data[0][1])
|
msg = email.message_from_bytes(data[0][1])
|
||||||
for part in msg.walk():
|
for part in msg.walk():
|
||||||
if part.get_filename():
|
if part.get_filename():
|
||||||
# ist ein Attachment
|
# let´s define parts with filename as attachments
|
||||||
filename = email.header.decode_header(part.get_filename())
|
filename = email.header.decode_header(part.get_filename())
|
||||||
if filename[0][1]:
|
if filename[0][1]:
|
||||||
# Encoded
|
# Encoded -> decode
|
||||||
filename = filename[0][0].decode(filename[0][1])
|
filename = filename[0][0].decode(filename[0][1])
|
||||||
else:
|
else:
|
||||||
# Nicht encoded
|
# not encoded
|
||||||
filename = filename[0][0]
|
filename = filename[0][0]
|
||||||
results.append({
|
results.append({
|
||||||
'filename': filename,
|
'filename': filename,
|
||||||
'content-type': part.get_content_type(), # Ist das wirklich wahr?
|
'content-type': part.get_content_type(),
|
||||||
'content': part.get_payload(decode=True)
|
'content': part.get_payload(decode=True)
|
||||||
})
|
})
|
||||||
# Ende if part.get_filename()
|
# End if part.get_filename()
|
||||||
return results
|
return results
|
||||||
|
|
||||||
|
def append_message(self,message):
|
||||||
|
rv, data = self.mailbox.append(
|
||||||
|
self.imap_mailbox,
|
||||||
|
'UNSEEN',
|
||||||
|
imaplib.Time2Internaldate(time.time()),
|
||||||
|
str(message).encode('utf-8')
|
||||||
|
)
|
||||||
|
if rv != 'OK':
|
||||||
|
raise IMAPmailboxException("ERROR appending message!")
|
||||||
|
|
||||||
|
|||||||
@ -64,9 +64,9 @@ class ResAttachment(GulagResource):
|
|||||||
class ResRSPAMDImporter(GulagResource):
|
class ResRSPAMDImporter(GulagResource):
|
||||||
def post(self,mailbox_id):
|
def post(self,mailbox_id):
|
||||||
try:
|
try:
|
||||||
self.gulag.rspamd_http2smtp(mailbox_id)
|
self.gulag.rspamd_http2imap(mailbox_id)
|
||||||
# TODO: Response mit Location-Header?
|
# TODO: Response mit Location-Header?
|
||||||
return {"resource: ": "HTTP2SMTP for RSPAMD"}
|
return {"resource: ": "HTTP2IMAP for RSPAMD"}
|
||||||
except GulagException as e:
|
except GulagException as e:
|
||||||
abort(400, message=e.message)
|
abort(400, message=e.message)
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user