keep Reply-To header, replace it by a reverse-alias
This commit is contained in:
parent
8e72d79837
commit
67cd7ae3d4
|
@ -260,6 +260,52 @@ def get_or_create_contact(from_header: str, mail_from: str, alias: Alias) -> Con
|
||||||
return contact
|
return contact
|
||||||
|
|
||||||
|
|
||||||
|
def get_or_create_reply_to_contact(
|
||||||
|
reply_to_header: str, alias: Alias
|
||||||
|
) -> Optional[Contact]:
|
||||||
|
"""
|
||||||
|
Get or create the contact for the Reply-To header
|
||||||
|
"""
|
||||||
|
name, address = parseaddr_unicode(reply_to_header)
|
||||||
|
|
||||||
|
if not is_valid_email(address):
|
||||||
|
LOG.w(
|
||||||
|
"invalid reply-to address %s. Parse from %s",
|
||||||
|
address,
|
||||||
|
reply_to_header,
|
||||||
|
)
|
||||||
|
return None
|
||||||
|
|
||||||
|
address = sanitize_email(address)
|
||||||
|
|
||||||
|
contact = Contact.get_by(alias_id=alias.id, website_email=address)
|
||||||
|
if contact:
|
||||||
|
return contact
|
||||||
|
else:
|
||||||
|
LOG.d(
|
||||||
|
"create contact %s for alias %s via reply-to header",
|
||||||
|
address,
|
||||||
|
alias,
|
||||||
|
reply_to_header,
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
contact = Contact.create(
|
||||||
|
user_id=alias.user_id,
|
||||||
|
alias_id=alias.id,
|
||||||
|
website_email=address,
|
||||||
|
name=name,
|
||||||
|
reply_email=generate_reply_email(address, alias.user),
|
||||||
|
)
|
||||||
|
db.session.commit()
|
||||||
|
except IntegrityError:
|
||||||
|
LOG.w("Contact %s %s already exist", alias, address)
|
||||||
|
db.session.rollback()
|
||||||
|
contact = Contact.get_by(alias_id=alias.id, website_email=address)
|
||||||
|
|
||||||
|
return contact
|
||||||
|
|
||||||
|
|
||||||
def replace_header_when_forward(msg: Message, alias: Alias, header: str):
|
def replace_header_when_forward(msg: Message, alias: Alias, header: str):
|
||||||
"""
|
"""
|
||||||
Replace CC or To header by Reply emails in forward phase
|
Replace CC or To header by Reply emails in forward phase
|
||||||
|
@ -510,20 +556,20 @@ def handle_forward(envelope, msg: Message, rcpt_to: str) -> List[Tuple[bool, str
|
||||||
# handle_email_sent_to_ourself(alias, mb, msg, user)
|
# handle_email_sent_to_ourself(alias, mb, msg, user)
|
||||||
# return [(True, "250 Message accepted for delivery")]
|
# return [(True, "250 Message accepted for delivery")]
|
||||||
|
|
||||||
LOG.d("Create or get contact for from:%s reply-to:%s", msg["From"], msg["Reply-To"])
|
from_header = str(msg["From"])
|
||||||
# prefer using Reply-To when creating contact
|
LOG.d("Create or get contact for from_header:%s", from_header)
|
||||||
if msg["Reply-To"]:
|
|
||||||
# force convert header to string, sometimes contact_from_header is Header object
|
|
||||||
from_header = str(msg["Reply-To"])
|
|
||||||
|
|
||||||
# alert phishing attempt when reply-to = alias
|
|
||||||
if from_header == alias.email:
|
|
||||||
LOG.e("Reply-to same as alias %s", alias)
|
|
||||||
else:
|
|
||||||
from_header = str(msg["From"])
|
|
||||||
|
|
||||||
contact = get_or_create_contact(from_header, envelope.mail_from, alias)
|
contact = get_or_create_contact(from_header, envelope.mail_from, alias)
|
||||||
|
|
||||||
|
reply_to_contact = None
|
||||||
|
if msg["Reply-To"]:
|
||||||
|
reply_to = str(msg["Reply-To"])
|
||||||
|
LOG.d("Create or get contact for from_header:%s", reply_to)
|
||||||
|
# ignore when reply-to = alias
|
||||||
|
if reply_to == alias.email:
|
||||||
|
LOG.i("Reply-to same as alias %s", alias)
|
||||||
|
else:
|
||||||
|
reply_to_contact = get_or_create_reply_to_contact(reply_to, alias)
|
||||||
|
|
||||||
if not alias.enabled:
|
if not alias.enabled:
|
||||||
LOG.d("%s is disabled, do not forward", alias)
|
LOG.d("%s is disabled, do not forward", alias)
|
||||||
EmailLog.create(
|
EmailLog.create(
|
||||||
|
@ -553,12 +599,7 @@ def handle_forward(envelope, msg: Message, rcpt_to: str) -> List[Tuple[bool, str
|
||||||
# create a copy of message for each forward
|
# create a copy of message for each forward
|
||||||
ret.append(
|
ret.append(
|
||||||
forward_email_to_mailbox(
|
forward_email_to_mailbox(
|
||||||
alias,
|
alias, copy(msg), contact, envelope, mailbox, user, reply_to_contact
|
||||||
copy(msg),
|
|
||||||
contact,
|
|
||||||
envelope,
|
|
||||||
mailbox,
|
|
||||||
user,
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -572,6 +613,7 @@ def forward_email_to_mailbox(
|
||||||
envelope,
|
envelope,
|
||||||
mailbox,
|
mailbox,
|
||||||
user,
|
user,
|
||||||
|
reply_to_contact: Optional[Contact],
|
||||||
) -> (bool, str):
|
) -> (bool, str):
|
||||||
LOG.d("Forward %s -> %s -> %s", contact, alias, mailbox)
|
LOG.d("Forward %s -> %s -> %s", contact, alias, mailbox)
|
||||||
|
|
||||||
|
@ -731,6 +773,12 @@ def forward_email_to_mailbox(
|
||||||
add_or_replace_header(msg, "From", new_from_header)
|
add_or_replace_header(msg, "From", new_from_header)
|
||||||
LOG.d("From header, new:%s, old:%s", new_from_header, contact_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"]
|
||||||
|
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)
|
||||||
|
|
||||||
# replace CC & To emails by reverse-alias for all emails that are not alias
|
# replace CC & To emails by reverse-alias for all emails that are not alias
|
||||||
replace_header_when_forward(msg, alias, "Cc")
|
replace_header_when_forward(msg, alias, "Cc")
|
||||||
replace_header_when_forward(msg, alias, "To")
|
replace_header_when_forward(msg, alias, "To")
|
||||||
|
|
Loading…
Reference in New Issue