mirror of
https://github.com/chillout2k/gulag.git
synced 2025-12-13 16:00:18 +00:00
Bounce a QuarMail
This commit is contained in:
parent
46a6eaccae
commit
4d93d33e34
@ -38,7 +38,7 @@ class Mailrelay:
|
|||||||
self.smtp_user = mr_ref['smtp_user']
|
self.smtp_user = mr_ref['smtp_user']
|
||||||
if 'smtp_pass' not in mr_ref:
|
if 'smtp_pass' not in mr_ref:
|
||||||
raise MailrelayException("'smtp_pass' is mandatory!")
|
raise MailrelayException("'smtp_pass' is mandatory!")
|
||||||
self.smtp_pass = mb_ref['imap_pass']
|
self.smtp_pass = mr_ref['smtp_pass']
|
||||||
if 'comment' in mr_ref:
|
if 'comment' in mr_ref:
|
||||||
self.comment = mr_ref['comment']
|
self.comment = mr_ref['comment']
|
||||||
if 'href' in mr_ref:
|
if 'href' in mr_ref:
|
||||||
@ -99,6 +99,9 @@ class Mailbox:
|
|||||||
if 'imap_separator' not in mb_ref:
|
if 'imap_separator' not in mb_ref:
|
||||||
raise MailboxException("'imap_separator' is mandatory!")
|
raise MailboxException("'imap_separator' is mandatory!")
|
||||||
self.imap_seperator = mb_ref['imap_separator']
|
self.imap_seperator = mb_ref['imap_separator']
|
||||||
|
if 'mailrelay_id' not in mb_ref:
|
||||||
|
raise MailboxException("'mailrelay_id' is mandatory!")
|
||||||
|
self.mailrelay_id = mb_ref['mailrelay_id']
|
||||||
if 'comment' in mb_ref:
|
if 'comment' in mb_ref:
|
||||||
self.comment = mb_ref['comment']
|
self.comment = mb_ref['comment']
|
||||||
if 'href' in mb_ref:
|
if 'href' in mb_ref:
|
||||||
|
|||||||
29
app/Gulag.py
29
app/Gulag.py
@ -4,6 +4,7 @@ from GulagDB import (
|
|||||||
GulagDB,GulagDBException,GulagDBNotFoundException,GulagDBBadInputException
|
GulagDB,GulagDBException,GulagDBNotFoundException,GulagDBBadInputException
|
||||||
)
|
)
|
||||||
from GulagMailbox import IMAPmailbox,IMAPmailboxException
|
from GulagMailbox import IMAPmailbox,IMAPmailboxException
|
||||||
|
from GulagMailrelay import GulagMailrelay,GulagMailrelayException
|
||||||
from GulagUtils import whoami,extract_uris,extract_fqdn
|
from GulagUtils import whoami,extract_uris,extract_fqdn
|
||||||
import ssdeep, hashlib
|
import ssdeep, hashlib
|
||||||
|
|
||||||
@ -305,16 +306,10 @@ class Gulag:
|
|||||||
raise GulagException(whoami(self) + e.message) from e
|
raise GulagException(whoami(self) + e.message) from e
|
||||||
imap_mb.close()
|
imap_mb.close()
|
||||||
# end for mailboxes
|
# end for mailboxes
|
||||||
if 'rfc822_message' in args:
|
|
||||||
return {
|
return {
|
||||||
"quarmails": qms_db,
|
"quarmails": qms_db,
|
||||||
"rfc822_messages": mailboxes
|
"rfc822_messages": mailboxes
|
||||||
}
|
}
|
||||||
elif 'headers' in args:
|
|
||||||
return {
|
|
||||||
"quarmails": qms_db,
|
|
||||||
"headers": mailboxes
|
|
||||||
}
|
|
||||||
|
|
||||||
def get_quarmail(self,args):
|
def get_quarmail(self,args):
|
||||||
qm_db = None
|
qm_db = None
|
||||||
@ -344,8 +339,8 @@ class Gulag:
|
|||||||
qm_db['imap_uid']
|
qm_db['imap_uid']
|
||||||
).decode("utf-8")
|
).decode("utf-8")
|
||||||
elif 'headers' in args:
|
elif 'headers' in args:
|
||||||
qm_db['headers'] = imap_mb.get_headers(
|
qm_db['rfc822_message'] = imap_mb.get_headers(
|
||||||
qmat_db['imap_uid']
|
qm_db['imap_uid']
|
||||||
)
|
)
|
||||||
imap_mb.close()
|
imap_mb.close()
|
||||||
return qm_db
|
return qm_db
|
||||||
@ -431,16 +426,28 @@ class Gulag:
|
|||||||
|
|
||||||
def bounce_quarmail(self,args):
|
def bounce_quarmail(self,args):
|
||||||
try:
|
try:
|
||||||
|
# get quarmail object with headers from mailbox
|
||||||
quarmail = self.get_quarmail({
|
quarmail = self.get_quarmail({
|
||||||
"quarmail_id": args['quarmail_id'],
|
"quarmail_id": args['quarmail_id'],
|
||||||
"rfc822_message": True
|
"headers": True
|
||||||
})
|
})
|
||||||
# TODO: bounce quarmail headers-only to quarmail['env_from']
|
# the mailbox reference holds the appropriate mailrelay_id
|
||||||
# TODO: self.delete_quarmail() if arg['purge']
|
mailbox_ref = self.db.get_mailbox(quarmail['mailbox_id'])
|
||||||
|
logging.info(whoami(self)+"mailrelay_id: "+str(mailbox_ref['mailrelay_id']))
|
||||||
|
mailrelay_ref = self.db.get_mailrelay(mailbox_ref['mailrelay_id'])
|
||||||
|
logging.info(whoami(self) + str(mailrelay_ref))
|
||||||
|
mailrelay = GulagMailrelay(mailrelay_ref)
|
||||||
|
mailrelay.bounce_quarmail(quarmail)
|
||||||
|
if 'purge' in args:
|
||||||
|
self.delete_quarmail({"quarmail_id": args['quarmail_id']})
|
||||||
except GulagNotFoundException as e:
|
except GulagNotFoundException as e:
|
||||||
raise GulagNotFoundException(whoami(self) + e.message) from e
|
raise GulagNotFoundException(whoami(self) + e.message) from e
|
||||||
except GulagException as e:
|
except GulagException as e:
|
||||||
raise GulagException(whoami(self) + e.message) from e
|
raise GulagException(whoami(self) + e.message) from e
|
||||||
|
except GulagDBNotFoundException as e:
|
||||||
|
raise GulagNotFoundException(whoami(self) + e.message) from e
|
||||||
|
except GulagMailrelayException as e:
|
||||||
|
raise GulagException(whoami(self) + e.message) from e
|
||||||
|
|
||||||
def forward_quarmail(self,args):
|
def forward_quarmail(self,args):
|
||||||
try:
|
try:
|
||||||
|
|||||||
@ -179,7 +179,7 @@ class GulagDB:
|
|||||||
except mariadb.Error as e:
|
except mariadb.Error as e:
|
||||||
raise GulagDBException(whoami(self) + str(e.msg)) from e
|
raise GulagDBException(whoami(self) + str(e.msg)) from e
|
||||||
|
|
||||||
def get_mailrelay(self,mailbox_id):
|
def get_mailrelay(self,mailrelay_id):
|
||||||
try:
|
try:
|
||||||
cursor = self.conn.cursor()
|
cursor = self.conn.cursor()
|
||||||
cursor.execute(
|
cursor.execute(
|
||||||
|
|||||||
116
app/GulagMailrelay.py
Normal file
116
app/GulagMailrelay.py
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
from smtplib import (
|
||||||
|
SMTP,SMTPRecipientsRefused,SMTPHeloError,SMTPSenderRefused, SMTPDataError,
|
||||||
|
SMTPNotSupportedError
|
||||||
|
)
|
||||||
|
import email
|
||||||
|
from email.message import EmailMessage
|
||||||
|
from email.mime.multipart import MIMEMultipart
|
||||||
|
from email.mime.base import MIMEBase
|
||||||
|
from email.mime.text import MIMEText
|
||||||
|
from email.mime.message import MIMEMessage
|
||||||
|
from email.utils import formatdate
|
||||||
|
from email import policy
|
||||||
|
import time,sys
|
||||||
|
from GulagUtils import whoami
|
||||||
|
|
||||||
|
class GulagMailrelayException(Exception):
|
||||||
|
message = None
|
||||||
|
def __init__(self,message):
|
||||||
|
self.message = str(message)
|
||||||
|
|
||||||
|
class GulagMailrelay:
|
||||||
|
id = None
|
||||||
|
smtp_server = None
|
||||||
|
smtp_port = None
|
||||||
|
smtp_security = None
|
||||||
|
smtp_user = None
|
||||||
|
smtp_pass = None
|
||||||
|
mailrelay = None
|
||||||
|
|
||||||
|
def __init__(self,mailrelay_ref):
|
||||||
|
self.id = mailrelay_ref['id']
|
||||||
|
self.smtp_server = mailrelay_ref['smtp_server']
|
||||||
|
self.smtp_port = mailrelay_ref['smtp_port']
|
||||||
|
self.smtp_security = mailrelay_ref['smtp_security']
|
||||||
|
self.smtp_user = mailrelay_ref['smtp_user']
|
||||||
|
self.smtp_pass = mailrelay_ref['smtp_pass']
|
||||||
|
|
||||||
|
def release_quarmail(self,quarmail):
|
||||||
|
try:
|
||||||
|
# FIXME: SMTP transport security and authentication!
|
||||||
|
with SMTP(host=self.smtp_server,port=self.smtp_port) as self.mailrelay:
|
||||||
|
self.mailrelay.sendmail(
|
||||||
|
quarmail['env_from'],
|
||||||
|
quarmail['env_rcpt'],
|
||||||
|
quarmail['rfc822_message']
|
||||||
|
)
|
||||||
|
self.mailrelay.quit()
|
||||||
|
except (SMTPRecipientsRefused,SMTPHeloError,SMTPSenderRefused,
|
||||||
|
SMTPDataError,SMTPNotSupportedError) as e:
|
||||||
|
raise GulagMailrelayException(whoami(self) + e.message) from e
|
||||||
|
except TimeoutError as e:
|
||||||
|
raise GulagMailrelayException(whoami(self) + e.message) from e
|
||||||
|
except ConnectionRefusedError as e:
|
||||||
|
raise GulagMailrelayException(whoami(self) + e.strerror) from e
|
||||||
|
|
||||||
|
def bounce_quarmail(self,quarmail):
|
||||||
|
msg = None
|
||||||
|
if quarmail['env_from'] == '<>':
|
||||||
|
raise GulagMailrelayException(whoami(self) +
|
||||||
|
"Unwilling to double-bounce QuarMail("+quarmail['id']+")!"
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
# multipart/report
|
||||||
|
msg = MIMEMultipart('report', boundary='GULAG-DSN-BOUNDARY')
|
||||||
|
msg['Subject'] = 'Undelivered Mail Returned to Sender'
|
||||||
|
msg['From'] = 'GULAG MAILER-DAEMON (Mail Quarantine System) <>'
|
||||||
|
msg['To'] = quarmail['env_from']
|
||||||
|
msg['Auto-Submitted'] = 'auto-replied'
|
||||||
|
msg['Message-ID'] = '<TODO-something-random@kiss.ass>'
|
||||||
|
msg['Date'] = formatdate()
|
||||||
|
msg.preamble = 'This is a MIME-encapsulated message.\r\n'
|
||||||
|
# text/plain
|
||||||
|
nt = "This is the mail system at host TODO-GULAG-QUARANTINE.HOST\r\n\r\n"
|
||||||
|
nt += "I'm sorry to have to inform you that your message could not\r\n"
|
||||||
|
nt += "be delivered to one or more recipients. It's headers are attached "
|
||||||
|
nt += "below.\r\n\r\n"
|
||||||
|
nt += "For further assistance, please send mail to postmaster.\r\n\r\n"
|
||||||
|
nt += "If you do so, please include this problem report. You can\r\n"
|
||||||
|
nt += "delete your own text from the attached returned message.\r\n\r\n"
|
||||||
|
nt += "<"+quarmail['env_rcpt']+">: host GULAG-QUARANTINE.HOST said: 550\r\n"
|
||||||
|
nt += "Requested action not taken: DANGEROUS\r\n"
|
||||||
|
msg.attach(MIMEText(nt, 'plain'))
|
||||||
|
# message/delivery-status
|
||||||
|
dr = "Reporting-MTA: dns; GULAG-QUARANTINE.HOST\r\n"
|
||||||
|
dr += "Queue-ID: "+quarmail['mx_queue_id']+"\r\n"
|
||||||
|
dr += "Sender: rfc822; "+quarmail['env_from']+"\r\n"
|
||||||
|
dr += "Arrival-Date: "+quarmail['ctime']
|
||||||
|
dr += "Final-Recipient: rfc822;"+quarmail['env_rcpt']+"\r\n\r\n"
|
||||||
|
dr += "Original-Recipient: rfc822;"+quarmail['env_rcpt']+"\r\n"
|
||||||
|
dr += "Action: failed\r\n"
|
||||||
|
dr += "Status: 5.0.0\r\n"
|
||||||
|
dr += "Remote-MTA: dns; GULAG-QUARANTINE.HOST\r\n"
|
||||||
|
dr += "Diagnostic-Code: smtp; 550 Requested action not taken: DANGEROUS\r\n"
|
||||||
|
dr_part = MIMEBase('message','delivery-status')
|
||||||
|
dr_part.set_payload(dr)
|
||||||
|
#dr_part.policy = policy.compat32
|
||||||
|
#msg.attach(dr_part)
|
||||||
|
# message/rfc822
|
||||||
|
msg.attach(MIMEMessage(
|
||||||
|
email.message_from_bytes(quarmail['rfc822_message'])
|
||||||
|
))
|
||||||
|
except:
|
||||||
|
raise GulagMailrelayException(whoami(self) + str(sys.exc_info()))
|
||||||
|
try:
|
||||||
|
# FIXME: SMTP transport security and authentication!
|
||||||
|
with SMTP(host=self.smtp_server,port=self.smtp_port) as self.mailrelay:
|
||||||
|
self.mailrelay.sendmail('<>', quarmail['env_from'], msg.as_string())
|
||||||
|
self.mailrelay.quit()
|
||||||
|
return True
|
||||||
|
except (SMTPRecipientsRefused,SMTPHeloError,SMTPSenderRefused,
|
||||||
|
SMTPDataError,SMTPNotSupportedError) as e:
|
||||||
|
raise GulagMailrelayException(whoami(self) + e.message) from e
|
||||||
|
except TimeoutError as e:
|
||||||
|
raise GulagMailrelayException(whoami(self) + e.message) from e
|
||||||
|
except ConnectionRefusedError as e:
|
||||||
|
raise GulagMailrelayException(whoami(self) + e.strerror) from e
|
||||||
@ -1,26 +1,9 @@
|
|||||||
import sys,re,urllib
|
import sys,re,urllib
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlparse
|
||||||
from smtplib import SMTP
|
|
||||||
|
|
||||||
def whoami(obj):
|
def whoami(obj):
|
||||||
return type(obj).__name__ + "::" + sys._getframe(1).f_code.co_name + "(): "
|
return type(obj).__name__ + "::" + sys._getframe(1).f_code.co_name + "(): "
|
||||||
|
|
||||||
def send_mail(args):
|
|
||||||
try:
|
|
||||||
# FIXME: SMTP transport 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
|
|
||||||
print("TODO")
|
|
||||||
except TimeoutError as e:
|
|
||||||
raise Exception('xyz') from e
|
|
||||||
|
|
||||||
def extract_uris(input_text):
|
def extract_uris(input_text):
|
||||||
uris = {}
|
uris = {}
|
||||||
uri_pattern = r'(https?:\/\/[^\s<>"]+)'
|
uri_pattern = r'(https?:\/\/[^\s<>"]+)'
|
||||||
|
|||||||
@ -8,7 +8,7 @@ from Resources import (ResRoot,ResMailboxes,
|
|||||||
ResQuarMails,ResQuarMail,ResQuarMailAttachments,
|
ResQuarMails,ResQuarMail,ResQuarMailAttachments,
|
||||||
ResQuarMailAttachment,ResAttachments,ResAttachment,
|
ResQuarMailAttachment,ResAttachments,ResAttachment,
|
||||||
ResRspamd2Mailbox,ResQuarMailURIs,ResQuarMailURI,
|
ResRspamd2Mailbox,ResQuarMailURIs,ResQuarMailURI,
|
||||||
ResMailradar2Mailbox,ResQuarMailRelease
|
ResMailradar2Mailbox,ResQuarMailRelease,ResQuarMailBounce
|
||||||
)
|
)
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser.add_argument('--config', required=True, help="Path to config file")
|
parser.add_argument('--config', required=True, help="Path to config file")
|
||||||
@ -44,6 +44,10 @@ try:
|
|||||||
'/api/v1/quarmails/<int:quarmail_id>/release',
|
'/api/v1/quarmails/<int:quarmail_id>/release',
|
||||||
resource_class_kwargs={'gulag_object': gulag}
|
resource_class_kwargs={'gulag_object': gulag}
|
||||||
)
|
)
|
||||||
|
api.add_resource(ResQuarMailBounce,
|
||||||
|
'/api/v1/quarmails/<int:quarmail_id>/bounce',
|
||||||
|
resource_class_kwargs={'gulag_object': gulag}
|
||||||
|
)
|
||||||
api.add_resource(ResQuarMailAttachments,
|
api.add_resource(ResQuarMailAttachments,
|
||||||
'/api/v1/quarmails/<int:quarmail_id>/attachments',
|
'/api/v1/quarmails/<int:quarmail_id>/attachments',
|
||||||
resource_class_kwargs={'gulag_object': gulag}
|
resource_class_kwargs={'gulag_object': gulag}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user