80 lines
2.5 KiB
Python
Executable File
80 lines
2.5 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""DKIM signing email sender - replaces raw PMTA relay
|
|
Usage: python3 dkim_helper.py <to_email> <from_email> <from_name> <subject> <body_html> <unsub_url> <return_path> <domain>
|
|
"""
|
|
import sys,smtplib,uuid,datetime,socket,dkim
|
|
from email.mime.text import MIMEText
|
|
from email.mime.multipart import MIMEMultipart
|
|
|
|
# Force IPv4
|
|
orig=socket.getaddrinfo
|
|
def ipv4(*a,**k):return[r for r in orig(*a,**k)if r[0]==socket.AF_INET]
|
|
socket.getaddrinfo=ipv4
|
|
|
|
to_email=sys.argv[1]
|
|
from_email=sys.argv[2]
|
|
from_name=sys.argv[3]
|
|
subject=sys.argv[4]
|
|
body_html=sys.argv[5] if len(sys.argv)>5 else "<p>Test</p>"
|
|
unsub_url=sys.argv[6] if len(sys.argv)>6 else ""
|
|
return_path=sys.argv[7] if len(sys.argv)>7 else from_email
|
|
domain=sys.argv[8] if len(sys.argv)>8 else "culturellemejean.charity"
|
|
|
|
msg=MIMEMultipart("alternative")
|
|
msg["From"]=f"{from_name} <{from_email}>"
|
|
msg["To"]=to_email
|
|
msg["Subject"]=subject
|
|
msg["Message-ID"]=f"<{uuid.uuid4()}@{domain}>"
|
|
msg["Date"]=datetime.datetime.utcnow().strftime("%a, %d %b %Y %H:%M:%S +0000")
|
|
msg["MIME-Version"]="1.0"
|
|
if unsub_url:
|
|
msg["List-Unsubscribe"]=f"<{unsub_url}>"
|
|
msg.attach(MIMEText(body_html,"html","utf-8"))
|
|
|
|
raw=msg.as_bytes()
|
|
|
|
# DKIM sign
|
|
try:
|
|
with open("/etc/pmta/dkim_key.pem","rb") as f:
|
|
privkey=f.read()
|
|
sig=dkim.sign(raw,b"wevads",domain.encode(),privkey,include_headers=[b"From",b"To",b"Subject",b"Date",b"Message-ID",b"MIME-Version"])
|
|
raw=sig+raw
|
|
except Exception as e:
|
|
print(f"DKIM_WARN:{e}",file=sys.stderr)
|
|
|
|
# Detect target MX
|
|
target=to_email.split("@")[1].lower()
|
|
mx_map={"gmail.com":"gmail-smtp-in.l.google.com","googlemail.com":"gmail-smtp-in.l.google.com"}
|
|
|
|
import subprocess
|
|
if target in mx_map:
|
|
mx_host=mx_map[target]
|
|
else:
|
|
try:
|
|
r=subprocess.run(["dig","+short","MX",target],capture_output=True,text=True,timeout=5)
|
|
lines=[l.strip() for l in r.stdout.strip().split("\n") if l.strip()]
|
|
if lines:
|
|
mx_host=sorted(lines,key=lambda x:int(x.split()[0]))[0].split()[1].rstrip(".")
|
|
else:
|
|
mx_host=target
|
|
except:
|
|
mx_host=target
|
|
|
|
try:
|
|
s=smtplib.SMTP(mx_host,25,timeout=15)
|
|
s.ehlo(domain)
|
|
s.sendmail(return_path,to_email,raw)
|
|
s.quit()
|
|
print(f"OK:{mx_host}")
|
|
except Exception as e:
|
|
# Fallback: try PMTA
|
|
try:
|
|
s2=smtplib.SMTP("127.0.0.1",25,timeout=5)
|
|
s2.ehlo(domain)
|
|
s2.sendmail(return_path,to_email,raw)
|
|
s2.quit()
|
|
print(f"OK:pmta-fallback")
|
|
except Exception as e2:
|
|
print(f"FAIL:{e}|{e2}")
|
|
sys.exit(1)
|