@ -57,10 +57,9 @@ class IdnaEmail(db.TypeDecorator):
def process_bind_param ( self , value , dialect ) :
def process_bind_param ( self , value , dialect ) :
""" encode unicode domain part of email address to punycode """
""" encode unicode domain part of email address to punycode """
localpart , domain_name = value . rsplit( ' @ ' , 1 )
localpart , domain_name = value . lower( ) . rsplit( ' @ ' , 1 )
if ' @ ' in localpart :
if ' @ ' in localpart :
raise ValueError ( ' email local part must not contain " @ " ' )
raise ValueError ( ' email local part must not contain " @ " ' )
domain_name = domain_name . lower ( )
return f ' { localpart } @ { idna . encode ( domain_name ) . decode ( " ascii " ) } '
return f ' { localpart } @ { idna . encode ( domain_name ) . decode ( " ascii " ) } '
def process_result_value ( self , value , dialect ) :
def process_result_value ( self , value , dialect ) :
@ -277,6 +276,7 @@ class Domain(Base):
def has_email ( self , localpart ) :
def has_email ( self , localpart ) :
""" checks if localpart is configured for domain """
""" checks if localpart is configured for domain """
localpart = localpart . lower ( )
for email in chain ( self . users , self . aliases ) :
for email in chain ( self . users , self . aliases ) :
if email . localpart == localpart :
if email . localpart == localpart :
return True
return True
@ -355,8 +355,8 @@ class Email(object):
@email.setter
@email.setter
def email ( self , value ) :
def email ( self , value ) :
""" setter for email - sets _email, localpart and domain_name at once """
""" setter for email - sets _email, localpart and domain_name at once """
self . localpart, self . domain_name = value . rsplit ( ' @ ' , 1 )
self . _email = value . lower ( )
self . _email = value
self . localpart, self . domain_name = self . _email . rsplit ( ' @ ' , 1 )
@staticmethod
@staticmethod
def _update_localpart ( target , value , * _ ) :
def _update_localpart ( target , value , * _ ) :
@ -389,8 +389,7 @@ class Email(object):
def resolve_domain ( cls , email ) :
def resolve_domain ( cls , email ) :
""" resolves domain alternative to real domain """
""" resolves domain alternative to real domain """
localpart , domain_name = email . rsplit ( ' @ ' , 1 ) if ' @ ' in email else ( None , email )
localpart , domain_name = email . rsplit ( ' @ ' , 1 ) if ' @ ' in email else ( None , email )
alternative = Alternative . query . get ( domain_name )
if alternative := Alternative . query . get ( domain_name ) :
if alternative :
domain_name = alternative . domain_name
domain_name = alternative . domain_name
return ( localpart , domain_name )
return ( localpart , domain_name )
@ -401,12 +400,14 @@ class Email(object):
localpart_stripped = None
localpart_stripped = None
stripped_alias = None
stripped_alias = None
if os . environ . get ( ' RECIPIENT_DELIMITER ' ) in localpart :
delim = os . environ . get ( ' RECIPIENT_DELIMITER ' )
localpart_stripped = localpart . rsplit ( os . environ . get ( ' RECIPIENT_DELIMITER ' ) , 1 ) [ 0 ]
if delim in localpart :
localpart_stripped = localpart . rsplit ( delim , 1 ) [ 0 ]
user = User . query . get ( f ' { localpart } @ { domain_name } ' )
user = User . query . get ( f ' { localpart } @ { domain_name } ' )
if not user and localpart_stripped :
if not user and localpart_stripped :
user = User . query . get ( f ' { localpart_stripped } @ { domain_name } ' )
user = User . query . get ( f ' { localpart_stripped } @ { domain_name } ' )
if user :
if user :
email = f ' { localpart } @ { domain_name } '
email = f ' { localpart } @ { domain_name } '
@ -416,15 +417,15 @@ class Email(object):
destination . append ( email )
destination . append ( email )
else :
else :
destination = [ email ]
destination = [ email ]
return destination
return destination
pure_alias = Alias . resolve ( localpart , domain_name )
pure_alias = Alias . resolve ( localpart , domain_name )
stripped_alias = Alias . resolve ( localpart_stripped , domain_name )
if pure_alias and not pure_alias . wildcard :
if pure_alias and not pure_alias . wildcard :
return pure_alias . destination
return pure_alias . destination
if stripped_alias :
if stripped_alias := Alias . resolve ( localpart_stripped , domain_name ) :
return stripped_alias . destination
return stripped_alias . destination
if pure_alias :
if pure_alias :