refactor: use headers.py

This commit is contained in:
Son 2021-10-11 12:10:18 +02:00
parent 9bb83fe3e2
commit 5821294ae9
3 changed files with 62 additions and 50 deletions

View File

@ -3,3 +3,21 @@ MESSAGE_ID = "Message-ID"
IN_REPLY_TO = "In-Reply-To"
REFERENCES = "References"
DATE = "date"
SUBJECT = "Subject"
FROM = "From"
TO = "To"
CONTENT_TYPE = "Content-Type"
MIME_VERSION = "Mime-Version"
REPLY_TO = "Reply-To"
RECEIVED = "Received"
CC = "Cc"
DKIM_SIGNATURE = "DKIM-Signature"
X_SPAM_STATUS = "X-Spam-Status"
# headers used to DKIM sign in order of preference
DKIM_HEADERS = [
[MESSAGE_ID.encode(), DATE.encode(), SUBJECT.encode(), FROM.encode(), TO.encode()],
[FROM.encode(), TO.encode()],
[MESSAGE_ID.encode(), DATE.encode()],
[FROM.encode()],
]

View File

@ -54,6 +54,7 @@ from app.config import (
ALIAS_AUTOMATIC_DISABLE,
)
from app.dns_utils import get_mx_domains
from app.email import headers
from app.extensions import db
from app.log import LOG
from app.models import (
@ -275,15 +276,15 @@ def send_email(
html = plaintext.replace("\n", "<br>")
msg.attach(MIMEText(html, "html"))
msg["Subject"] = subject
msg["From"] = f"{SUPPORT_NAME} <{SUPPORT_EMAIL}>"
msg["To"] = to_email
msg[headers.SUBJECT] = subject
msg[headers.FROM] = f"{SUPPORT_NAME} <{SUPPORT_EMAIL}>"
msg[headers.TO] = to_email
msg_id_header = make_msgid()
msg["Message-ID"] = msg_id_header
msg[headers.MESSAGE_ID] = msg_id_header
date_header = formatdate()
msg["Date"] = date_header
msg[headers.DATE] = date_header
if unsubscribe_link:
add_or_replace_header(msg, "List-Unsubscribe", f"<{unsubscribe_link}>")
@ -408,17 +409,8 @@ def get_email_domain_part(address):
return address[address.find("@") + 1 :]
# headers used to DKIM sign in order of preference
_DKIM_HEADERS = [
[b"Message-ID", b"Date", b"Subject", b"From", b"To"],
[b"From", b"To"],
[b"Message-ID", b"Date"],
[b"From"],
]
def add_dkim_signature(msg: Message, email_domain: str):
for dkim_headers in _DKIM_HEADERS:
for dkim_headers in headers.DKIM_HEADERS:
try:
add_dkim_signature_with_header(msg, email_domain, dkim_headers)
return
@ -457,7 +449,7 @@ def add_dkim_signature_with_header(
# remove linebreaks from sig
sig = sig.replace("\n", " ").replace("\r", "")
msg["DKIM-Signature"] = sig[len("DKIM-Signature: ") :]
msg[headers.DKIM_SIGNATURE] = sig[len("DKIM-Signature: ") :]
def add_or_replace_header(msg: Message, header: str, value: str):
@ -686,7 +678,7 @@ def get_spam_info(msg: Message, max_score=None) -> (bool, str):
DKIM_VALID_AU,RCVD_IN_DNSWL_BLOCKED,RCVD_IN_MSPIKE_H2,SPF_PASS,
URIBL_BLOCKED autolearn=unavailable autolearn_force=no version=3.4.2```
"""
spamassassin_status = msg["X-Spam-Status"]
spamassassin_status = msg[headers.X_SPAM_STATUS]
if not spamassassin_status:
return False, ""
@ -1164,7 +1156,7 @@ def spf_pass(
r[0],
ip,
)
subject = get_header_unicode(msg["Subject"])
subject = get_header_unicode(msg[headers.SUBJECT])
send_email_with_rate_control(
user,
ALERT_SPF,
@ -1214,9 +1206,9 @@ def sl_sendmail(
if NOT_SEND_EMAIL:
LOG.d(
"send email with subject '%s', from '%s' to '%s'",
msg["Subject"],
msg["From"],
msg["To"],
msg[headers.SUBJECT],
msg[headers.FROM],
msg[headers.TO],
)
return
@ -1236,9 +1228,9 @@ def sl_sendmail(
"Sendmail mail_from:%s, rcpt_to:%s, header_from:%s, header_to:%s, header_cc:%s",
from_addr,
to_addr,
msg["From"],
msg["To"],
msg["Cc"],
msg[headers.FROM],
msg[headers.TO],
msg[headers.CC],
)
smtp.sendmail(
from_addr,
@ -1266,7 +1258,7 @@ def sl_sendmail(
def get_queue_id(msg: Message) -> Optional[str]:
"""Get the Postfix queue-id from a message"""
received_header = str(msg["Received"])
received_header = str(msg[headers.RECEIVED])
if not received_header:
return

View File

@ -445,13 +445,13 @@ def prepare_pgp_message(
_MIME_HEADERS,
)
if clone_msg["Content-Type"] is None:
if clone_msg[headers.CONTENT_TYPE] is None:
LOG.d("Content-Type missing")
clone_msg["Content-Type"] = "text/plain"
clone_msg[headers.CONTENT_TYPE] = "text/plain"
if clone_msg["Mime-Version"] is None:
if clone_msg[headers.MIME_VERSION] is None:
LOG.d("Mime-Version missing")
clone_msg["Mime-Version"] = "1.0"
clone_msg[headers.MIME_VERSION] = "1.0"
first = MIMEApplication(
_subtype="pgp-encrypted", _encoder=encoders.encode_7or8bit, _data=""
@ -581,13 +581,13 @@ def handle_forward(envelope, msg: Message, rcpt_to: str) -> List[Tuple[bool, str
handle_email_sent_to_ourself(alias, mb, msg, user)
return [(True, status.E209)]
from_header = get_header_unicode(msg["From"])
from_header = get_header_unicode(msg[headers.FROM])
LOG.d("Create or get contact for from_header:%s", from_header)
contact = get_or_create_contact(from_header, envelope.mail_from, alias)
reply_to_contact = None
if msg["Reply-To"]:
reply_to = get_header_unicode(msg["Reply-To"])
if msg[headers.REPLY_TO]:
reply_to = get_header_unicode(msg[headers.REPLY_TO])
LOG.d("Create or get contact for from_header:%s", reply_to)
# ignore when reply-to = alias
if reply_to == alias.email:
@ -766,7 +766,7 @@ def forward_email_to_mailbox(
LOG.d("Encrypt message using mailbox %s", mailbox)
if mailbox.generic_subject:
LOG.d("Use a generic subject for %s", mailbox)
orig_subject = msg["Subject"]
orig_subject = msg[headers.SUBJECT]
orig_subject = get_header_unicode(orig_subject)
add_or_replace_header(msg, "Subject", mailbox.generic_subject)
msg = add_header(
@ -806,13 +806,13 @@ def forward_email_to_mailbox(
# change the from header so the sender comes from a reverse-alias
# so it can pass DMARC check
# replace the email part in from: header
contact_from_header = msg["From"]
contact_from_header = msg[headers.FROM]
new_from_header = contact.new_addr()
add_or_replace_header(msg, "From", new_from_header)
LOG.d("From header, new:%s, old:%s", new_from_header, contact_from_header)
if reply_to_contact:
reply_to_header = msg["Reply-To"]
reply_to_header = msg[headers.REPLY_TO]
new_reply_to_header = reply_to_contact.new_addr()
add_or_replace_header(msg, "Reply-To", new_reply_to_header)
LOG.d("Reply-To header, new:%s, old:%s", new_reply_to_header, reply_to_header)
@ -1048,11 +1048,11 @@ def handle_reply(envelope, msg: Message, rcpt_to: str) -> (bool, str):
LOG.d("make message id %s", message_id)
add_or_replace_header(
msg,
"Message-ID",
headers.MESSAGE_ID,
message_id,
)
date_header = formatdate()
msg["Date"] = date_header
msg[headers.DATE] = date_header
msg[_DIRECTION] = "Reply"
msg[_EMAIL_LOG_ID_HEADER] = str(email_log.id)
@ -1133,7 +1133,7 @@ def handle_unknown_mailbox(
"Reply email can only be used by mailbox. "
"Actual mail_from: %s. msg from header: %s, reverse-alias %s, %s %s %s",
envelope.mail_from,
msg["From"],
msg[headers.FROM],
reply_email,
alias,
user,
@ -1315,7 +1315,7 @@ def handle_hotmail_complaint(msg: Message) -> bool:
Return True if the complaint can be handled, False otherwise
"""
orig_msg = get_orig_message_from_hotmail_complaint(msg)
to_header = orig_msg["To"]
to_header = orig_msg[headers.TO]
if not to_header:
LOG.e("cannot find the alias")
return False
@ -1355,7 +1355,7 @@ def handle_yahoo_complaint(msg: Message) -> bool:
Return True if the complaint can be handled, False otherwise
"""
orig_msg = get_orig_message_from_yahoo_complaint(msg)
to_header = orig_msg["To"]
to_header = orig_msg[headers.TO]
if not to_header:
LOG.e("cannot find the alias")
return False
@ -1559,7 +1559,7 @@ def handle_spam(
def handle_unsubscribe(envelope: Envelope, msg: Message) -> str:
"""return the SMTP status"""
# format: alias_id:
subject = msg["Subject"]
subject = msg[headers.SUBJECT]
try:
# subject has the format {alias.id}=
if subject.endswith("="):
@ -1574,7 +1574,7 @@ def handle_unsubscribe(envelope: Envelope, msg: Message) -> str:
alias = Alias.get(alias_id)
except Exception:
LOG.w("Cannot parse alias from subject %s", msg["Subject"])
LOG.w("Cannot parse alias from subject %s", msg[headers.SUBJECT])
return status.E507
if not alias:
@ -1746,7 +1746,7 @@ def handle(envelope: Envelope) -> str:
if postfix_queue_id:
set_message_id(postfix_queue_id)
else:
LOG.d("Cannot parse Postfix queue ID from %s", msg["Received"])
LOG.d("Cannot parse Postfix queue ID from %s", msg[headers.RECEIVED])
if should_ignore(mail_from, rcpt_tos):
LOG.w("Ignore email mail_from=%s rcpt_to=%s", mail_from, rcpt_tos)
@ -1763,10 +1763,10 @@ def handle(envelope: Envelope) -> str:
"cc:%s, reply-to:%s, mail_options:%s, rcpt_options:%s",
mail_from,
rcpt_tos,
msg["From"],
msg["To"],
msg["Cc"],
msg["Reply-To"],
msg[headers.FROM],
msg[headers.TO],
msg[headers.CC],
msg[headers.REPLY_TO],
envelope.mail_options,
envelope.rcpt_options,
)
@ -1854,7 +1854,7 @@ def handle(envelope: Envelope) -> str:
return handle_bounce(envelope, email_log, msg)
# case where From: header is a reverse alias which should never happen
from_header = get_header_unicode(msg["From"])
from_header = get_header_unicode(msg[headers.FROM])
if from_header:
try:
_, from_header_address = parse_full_address(from_header)
@ -1926,14 +1926,16 @@ def handle(envelope: Envelope) -> str:
# Reply case
# recipient starts with "reply+" or "ra+" (ra=reverse-alias) prefix
if is_reply_email(rcpt_to):
LOG.d("Reply phase %s(%s) -> %s", mail_from, copy_msg["From"], rcpt_to)
LOG.d(
"Reply phase %s(%s) -> %s", mail_from, copy_msg[headers.FROM], rcpt_to
)
is_delivered, smtp_status = handle_reply(envelope, copy_msg, rcpt_to)
res.append((is_delivered, smtp_status))
else: # Forward case
LOG.d(
"Forward phase %s(%s) -> %s",
mail_from,
copy_msg["From"],
copy_msg[headers.FROM],
rcpt_to,
)
for is_delivered, smtp_status in handle_forward(