You may use the following
import re
p = re.compile(r'"([^"]+)"(?:\s+<([^<>]+)>)?')
test_str = '"Mr ABC" <mr@abc.com>, "Foo, Bar" <foo@bar.com>, "mr@xyz.com"'
print(re.findall(p, test_str))
Output: [('Mr ABC', 'mr@abc.com'), ('Foo, Bar', 'foo@bar.com'), ('mr@xyz.com', '')]
See IDEONE demo
The regex matches...
" - a double quote
([^"]+) - (Group 1) 1 or more characters other than a double quote
" - a double quote
Then, an optional non-capturing group is introduced with (?:...)? construct: (?:\s+<([^<>]+)>)?. It matches...
\s+ - 1 or more whitespace characters
< - an opening angle bracket
([^<>]+) - (Group 2) 1 or more characters other than opening or closing angle brackets
> - a closing angle bracket
The re.findall function gets all capture groups into a list of tuples:
If one or more groups are present in the pattern, return a list of groups; this will be a list of tuples if the pattern has more than one group.
UPDATE:
In case you need to make sure the email is the second element in the tuple, use this code (see demo):
lst = re.findall(p, test_str)
print([(tpl[1], tpl[0]) if not tpl[1] else tpl for tpl in lst])
# => [('Mr ABC', 'mr@abc.com'), ('Foo, Bar', 'foo@bar.com'), ('', 'mr@xyz.com')]