85 lines
2.3 KiB
Python
85 lines
2.3 KiB
Python
import Milter
|
|
import sys
|
|
import traceback
|
|
import email
|
|
import json
|
|
|
|
class DsnProcessorMilter(Milter.Base):
|
|
def __init__(self):
|
|
self.mail_data: str = ""
|
|
|
|
def process_dsn(self, mail_data: str):
|
|
msg = email.message_from_string(mail_data)
|
|
recipients = []
|
|
for part in msg.walk():
|
|
if part.get_content_type() == "message/delivery-status":
|
|
for subpart in part.walk():
|
|
rcpt = {}
|
|
if 'Action' in subpart and 'Original-Recipient' in subpart:
|
|
rcpt["action"] = subpart['Action']
|
|
rcpt["orig_rcpt"] = subpart['Original-Recipient'].replace('rfc822;', '')
|
|
rcpt["diag_code"] = None
|
|
if 'Diagnostic-Code' in subpart:
|
|
rcpt["diag_code"] = subpart['Diagnostic-Code']
|
|
rcpt["status"] = None
|
|
if 'Status' in subpart:
|
|
rcpt["status"] = subpart['Status']
|
|
recipients.append(rcpt)
|
|
return recipients
|
|
|
|
# Not registered/used callbacks
|
|
@Milter.nocallback
|
|
def hello(self, heloname):
|
|
return Milter.CONTINUE
|
|
@Milter.nocallback
|
|
def data(self):
|
|
return Milter.CONTINUE
|
|
|
|
def connect(self, IPname, family, hostaddr):
|
|
print("CONN: Client: {}".format(hostaddr[0]))
|
|
return Milter.CONTINUE
|
|
|
|
# Mandatory callback
|
|
def envfrom(self, mailfrom, *str):
|
|
print("MAIL FROM: {}".format(mailfrom))
|
|
self.mail_data = ""
|
|
return Milter.CONTINUE
|
|
|
|
# Mandatory callback
|
|
def envrcpt(self, to, *str):
|
|
print("RCPT TO: {}".format(to))
|
|
return Milter.CONTINUE
|
|
|
|
def header(self, name, hval):
|
|
print("HDR: {0}: {1}".format(name, hval))
|
|
self.mail_data += "{0}: {1}\n".format(name, hval)
|
|
return Milter.CONTINUE
|
|
|
|
def eoh(self):
|
|
self.mail_data += "\n"
|
|
return Milter.CONTINUE
|
|
|
|
def body(self, chunk):
|
|
self.mail_data += chunk.decode()
|
|
return Milter.CONTINUE
|
|
|
|
def eom(self):
|
|
dsn_details = self.process_dsn(self.mail_data)
|
|
for d in dsn_details:
|
|
print(json.dumps(d))
|
|
return Milter.CONTINUE
|
|
|
|
def close(self):
|
|
print("CLOSE")
|
|
self.mail_data = ""
|
|
return Milter.CONTINUE
|
|
|
|
if __name__ == "__main__":
|
|
try:
|
|
timeout = 600
|
|
Milter.factory = DsnProcessorMilter
|
|
print("Starting dsn-processor-milter...")
|
|
Milter.runmilter("dsn-processor-milter", "inet:4321@127.0.0.1" , timeout, True)
|
|
except:
|
|
print("MAIN-EXCEPTION: {}".format(traceback.format_exc()))
|
|
sys.exit(1) |