use contact email when generating reply-email

This commit is contained in:
Son NK 2020-11-18 10:24:39 +01:00
parent e06c872bc0
commit 319078fceb
5 changed files with 37 additions and 15 deletions

View File

@ -407,7 +407,7 @@ def create_contact_route(alias_id):
alias_id=alias.id,
website_email=contact_email,
name=contact_name,
reply_email=generate_reply_email(),
reply_email=generate_reply_email(contact_email),
)
LOG.d("create reverse-alias for %s %s", contact_addr, alias)

View File

@ -203,7 +203,7 @@ def alias_contact_manager(alias_id):
alias_id=alias.id,
website_email=contact_email,
name=contact_name,
reply_email=generate_reply_email(),
reply_email=generate_reply_email(contact_email),
)
LOG.d("create reverse-alias for %s", contact_addr)

View File

@ -1,5 +1,6 @@
import email
import os
import random
import re
from email.header import decode_header
from email.message import Message
@ -727,19 +728,37 @@ def add_header(msg: Message, text_header, html_header) -> Message:
return msg
def generate_reply_email() -> str:
def generate_reply_email(contact_email: str) -> str:
"""
generate a reply_email (aka reverse-alias), make sure it isn't used by any contact
"""
# shorten email to avoid exceeding the 64 characters
# from https://tools.ietf.org/html/rfc5321#section-4.5.3
# "The maximum total length of a user name or other local-part is 64
# octets."
if contact_email:
# control char: 4 chars (ra+, +)
# random suffix: max 10 chars
# maximum: 64
contact_email = contact_email[:45]
contact_email = contact_email.replace("@", ".at.")
# not use while to avoid infinite loop
for _ in range(1000):
reply_email = f"ra+{random_string(25)}@{EMAIL_DOMAIN}"
if contact_email:
random_length = random.randint(5, 10)
reply_email = (
f"ra+{contact_email}+{random_string(random_length)}@{EMAIL_DOMAIN}"
)
else:
random_length = random.randint(10, 50)
reply_email = f"ra+{random_string(random_length)}@{EMAIL_DOMAIN}"
if not Contact.get_by(reply_email=reply_email):
return reply_email
# use UUID as fallback
reply_email = f"ra+{uuid4()}@{EMAIL_DOMAIN}"
return reply_email
raise Exception("Cannot generate reply email")
def is_reply_email(address: str) -> bool:

View File

@ -213,20 +213,17 @@ def get_or_create_contact(
contact_from_header,
)
reply_email = generate_reply_email()
try:
contact = Contact.create(
user_id=alias.user_id,
alias_id=alias.id,
website_email=contact_email,
name=contact_name,
reply_email=reply_email,
mail_from=mail_from,
from_header=contact_from_header,
)
if contact_email:
contact.reply_email = generate_reply_email()
contact.reply_email = generate_reply_email(contact_email)
else:
LOG.d("Create a contact with invalid email for %s", alias)
contact.reply_email = NOREPLY
@ -281,15 +278,13 @@ def replace_header_when_forward(msg: Message, alias: Alias, header: str):
header,
)
reply_email = generate_reply_email()
try:
contact = Contact.create(
user_id=alias.user_id,
alias_id=alias.id,
website_email=contact_email,
name=contact_name,
reply_email=reply_email,
reply_email=generate_reply_email(contact_email),
is_cc=header.lower() == "cc",
from_header=addr,
)

View File

@ -391,7 +391,15 @@ def test_to_bytes():
def test_generate_reply_email(flask_client):
reply_email = generate_reply_email()
reply_email = generate_reply_email("test@example.org")
# return something like
# ra+test.at.example.org+gjbnnddll@sl.local
assert reply_email.startswith("ra+test.at.example.org+")
assert reply_email.endswith(EMAIL_DOMAIN)
reply_email = generate_reply_email("")
# return something like
# ra+qdrcxzppngmvtajklnhqvvuyyzgkyityrzjwikk@sl.local
assert reply_email.startswith("ra+")
assert reply_email.endswith(EMAIL_DOMAIN)