Skip to content

Commit

Permalink
Merge pull request #177 from krazybean/AN-53
Browse files Browse the repository at this point in the history
AN-53 - Frontier SMTP yahoo validation
  • Loading branch information
krazybean committed Dec 13, 2017
2 parents 96cbf2c + 49d2235 commit 8462ca4
Show file tree
Hide file tree
Showing 8 changed files with 88 additions and 15 deletions.
4 changes: 2 additions & 2 deletions flanker/addresslib/address.py
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ def validate_address(addr_spec, metrics=False):
bstart = time()
plugin = plugin_for_esp(exchanger)
mtimes['custom_grammar'] = time() - bstart
if plugin and plugin.validate(addr_parts[0]) is False:
if plugin and plugin.validate(paddr) is False:
_log.warning('failed custom grammer check for %s/%s', addr_spec, plugin.__name__)
return None, mtimes

Expand Down Expand Up @@ -369,7 +369,7 @@ def validate_list(addr_list, as_tuple=False, metrics=False):
# lookup custom local-part grammar if it exists
plugin = plugin_for_esp(exchanger)
bstart = time()
if plugin and plugin.validate(paddr.mailbox) is False:
if plugin and plugin.validate(paddr) is False:
ulist.append(paddr.full_spec())
continue
mtimes['custom_grammar'] = time() - bstart
Expand Down
5 changes: 4 additions & 1 deletion flanker/addresslib/plugins/aol.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,10 @@
''', re.MULTILINE | re.VERBOSE)


def validate(localpart):
def validate(email_addr):
# Setup for handling EmailAddress type instead of literal string
localpart = email_addr.mailbox

# check string exists and not empty
if not localpart:
return False
Expand Down
5 changes: 4 additions & 1 deletion flanker/addresslib/plugins/gmail.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,10 @@
''', re.MULTILINE | re.VERBOSE)


def validate(localpart):
def validate(email_addr):
# Setup for handling EmailAddress type instead of literal string
localpart = email_addr.mailbox

# check string exists and not empty
if not localpart:
return False
Expand Down
5 changes: 4 additions & 1 deletion flanker/addresslib/plugins/google.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,10 @@
''', re.MULTILINE | re.VERBOSE)


def validate(localpart):
def validate(email_addr):
# Setup for handling EmailAddress type instead of literal string
localpart = email_addr.mailbox

# check string exists and not empty
if not localpart:
return False
Expand Down
5 changes: 4 additions & 1 deletion flanker/addresslib/plugins/hotmail.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,10 @@
''', re.MULTILINE | re.VERBOSE)


def validate(localpart):
def validate(email_addr):
# Setup for handling EmailAddress type instead of literal string
localpart = email_addr.mailbox

# check string exists and not empty
if not localpart:
return False
Expand Down
5 changes: 4 additions & 1 deletion flanker/addresslib/plugins/icloud.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,10 @@
''', re.MULTILINE | re.VERBOSE)


def validate(localpart):
def validate(email_addr):
# Setup for handling EmailAddress type instead of literal string
localpart = email_addr.mailbox

# check string exists and not empty
if not localpart:
return False
Expand Down
34 changes: 26 additions & 8 deletions flanker/addresslib/plugins/yahoo.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,14 +68,20 @@
\-
''', re.MULTILINE | re.VERBOSE)

YAHOO_MANAGED = ['yahoo.com', 'ymail.com', 'rocketmail.com']


def validate(email_addr):
# Setup for handling EmailAddress type instead of literal string
localpart = email_addr.mailbox
managed = managed_email(email_addr.hostname)

def validate(localpart):
# check string exists and not empty
if not localpart:
return False

# must start with letter
if len(localpart) < 1 or ALPHA.match(localpart[0]) is None:
if len(localpart) < 1 or (ALPHA.match(localpart[0]) is None and managed):
return False

# must end with letter or digit
Expand All @@ -84,13 +90,17 @@ def validate(localpart):

# only disposable addresses may contain hyphens
if HYPHEN.search(localpart):
return _validate_disposable(localpart)
return _validate_disposable(email_addr)

# otherwise, normal validation
return _validate_primary(localpart)
return _validate_primary(email_addr)


def _validate_primary(email_addr):
# Setup for handling EmailAddress type instead of literal string
localpart = email_addr.mailbox
managed = managed_email(email_addr.hostname)

def _validate_primary(localpart):
# length check
l = len(localpart)
if l < 4 or l > 32:
Expand All @@ -105,7 +115,7 @@ def _validate_primary(localpart):

# local-part must being with alpha
alpa = stream.get_token(ALPHA)
if alpa is None:
if alpa is None and managed:
return False

while True:
Expand All @@ -123,7 +133,11 @@ def _validate_primary(localpart):

return True

def _validate_disposable(localpart):
def _validate_disposable(email_addr):
# Setup for handling EmailAddress type instead of literal string
localpart = email_addr.mailbox
managed = managed_email(email_addr.hostname)

# length check (base + hyphen + keyword)
l = len(localpart)
if l < 3 or l > 65:
Expand All @@ -145,7 +159,7 @@ def _validate_disposable(localpart):

# must being with alpha
begin = stream.get_token(ALPHA)
if begin is None:
if begin is None and managed:
return False

while True:
Expand All @@ -167,3 +181,7 @@ def _validate_disposable(localpart):
return False

return True


def managed_email(hostname):
return hostname in YAHOO_MANAGED
40 changes: 40 additions & 0 deletions tests/addresslib/validator_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -253,3 +253,43 @@ def test_validate_address_metrics():
# assert_equal(addr.full_spec(), 'foo@[1.2.3.4]')
# mock_lookup_domain.assert_not_called()
# mock_connect_to_mail_exchanger.assert_called_once_with(['1.2.3.4'])

@patch('flanker.addresslib.validate.connect_to_mail_exchanger')
@patch('flanker.addresslib.validate.lookup_domain')
def test_mx_yahoo_dual_lookup(ld, cmx):
ld.return_value = ['mta7.am0.yahoodns.net', 'mta6.am0.yahoodns.net']
cmx.return_value = 'mta5.am0.yahoodns.net'

# Invalidate managed email response out of pattern
mailbox = '1testuser@yahoo.com'
addr = address.validate_address(mailbox)
assert_equal(type(addr), type(None))

# Same test but with validate_list
addr = address.validate_list([mailbox])
expected = 'flanker.addresslib.address:'
assert_equal(addr, [])

# Allow Yahoo MX unmanaged mailboxes to pass remaining patterns
mailbox = '8testuser@frontier.com'
addr = address.validate_address(mailbox)
assert_equal(addr, mailbox)

# Same test but with validate_list
expected = 'flanker.addresslib.address:'
addr = address.validate_list([mailbox])
assert_equal(addr, mailbox)


def test_mx_yahoo_manage_flag_toggle():
# Just checking if the domain provided from the sub is managed
mailbox = '1testuser@yahoo.com'
addr_obj = address.parse(mailbox)
managed = validate.yahoo.managed_email(addr_obj.hostname)
assert_equal(managed, True)

# Same but inversed, unmanaged yahoo mailbox
mailbox = '1testuser@frontier.com'
addr_obj = address.parse(mailbox)
managed = validate.yahoo.managed_email(addr_obj.hostname)
assert_equal(managed, False)

0 comments on commit 8462ca4

Please sign in to comment.