Skip to content

email.Utils.parseaddr fails to parse valid addresses #40889

Description

@melicertes
mannequin
BPO 1025395
Nosy @warsaw, @tiran, @merwok, @bitdancer, @vadmium, @thehesiod, @ioanatia
PRs
  • bpo-1025395: Fix email.utils.parseaddr to handle multiple hops #142
  • bpo-1025395: Fix email.utils.parseaddr to handle multiple hops #6917
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = None
    closed_at = None
    created_at = <Date 2004-09-09.20:43:42.000>
    labels = ['3.7', 'type-bug', 'library', 'expert-email']
    title = 'email.Utils.parseaddr fails to parse valid addresses'
    updated_at = <Date 2018-05-16.19:01:00.100>
    user = 'https://bugs.python.org/melicertes'

    bugs.python.org fields:

    activity = <Date 2018-05-16.19:01:00.100>
    actor = 'ioanatia'
    assignee = 'none'
    closed = False
    closed_date = None
    closer = None
    components = ['Library (Lib)', 'email']
    creation = <Date 2004-09-09.20:43:42.000>
    creator = 'melicertes'
    dependencies = []
    files = []
    hgrepos = []
    issue_num = 1025395
    keywords = ['patch']
    message_count = 10.0
    messages = ['22413', '59669', '59670', '59671', '59735', '59737', '59751', '59753', '301485', '301504']
    nosy_count = 10.0
    nosy_names = ['barry', 'melicertes', 'christian.heimes', 'sdgathman', 'eric.araujo', 'r.david.murray', 'sascha_silbe', 'martin.panter', 'thehesiod', 'ioanatia']
    pr_nums = ['142', '6917']
    priority = 'normal'
    resolution = None
    stage = 'patch review'
    status = 'open'
    superseder = None
    type = 'behavior'
    url = 'https://bugs.python.org/issue1025395'
    versions = ['Python 2.7', 'Python 3.2', 'Python 3.3', 'Python 3.6', 'Python 3.7']

    Linked PRs

    Activity

    1. melicertes commented on Sep 9, 2004

      melicertesmannequin
      MannequinAuthor

      email.Utils.parseaddr() does not successfully parse a
      field value into a (comment, address) pair if the
      address contains a source route with more than one hop.

      i.e., it is successfully parses this:

      "God" <@hop1.org:jeff@spec.org>

      to get the address <jeff@spec.org>, but it fails to do
      the same if supplied with a 2-hop source route:

      "God" <@hop1.org,@hop2.net:jeff@spec.org>

      In this case, it gets the comment ("God") right, but
      fails to extract the address.

      Multi-hop source routes, while deprecated, are still
      valid in rfc2822.

    2. added
      stdlibStandard Library Python modules in the Lib/ directory
      on Sep 9, 2004
    3. added
      stdlibStandard Library Python modules in the Lib/ directory
      on Sep 9, 2004
    4. sdgathman commented on Jan 10, 2008

      sdgathmanmannequin
      Mannequin

      # A quick and very dirty fix for common broken cases, with test cases.

      import rfc822
      
      def parseaddr(t):
        """Split email into Fullname and address.
        >>> parseaddr('user@example.com')
        ('', 'user@example.com')
        >>> parseaddr('"Full Name" <foo@example.com>')
        ('Full Name', 'foo@example.com')
        >>> parseaddr('spam@viagra.com <foo@example.com>')
        ('spam@viagra.com', 'foo@example.com')
        >>> parseaddr('"God" <@hop1.org,@hop2.net:jeff@spec.org>')
        ('God', 'jeff@spec.org')
        """
        #return email.Utils.parseaddr(t)
        res = rfc822.parseaddr(t)
        # dirty fix for some broken cases
        if not res[0]:
          pos = t.find('<')
          if pos > 0 and t[-1] == '>':
            addrspec = t[pos+1:-1]
            pos1 = addrspec.rfind(':')
            if pos1 > 0:
              addrspec = addrspec[pos1+1:]
            return rfc822.parseaddr('"%s" <%s>' % (t[:pos].strip(),addrspec))
        if not res[1]:
          pos = t.find('<')
          if pos > 0 and t[-1] == '>':
            addrspec = t[pos+1:-1]
            pos1 = addrspec.rfind(':')
            if pos1 > 0:
              addrspec = addrspec[pos1+1:]
            return rfc822.parseaddr('%s<%s>' % (t[:pos].strip(),addrspec))
        return res
    5. sdgathman commented on Jan 10, 2008

      sdgathmanmannequin
      Mannequin

      Ok, I see the '@' is technically not allowed in an atom. But it either
      needs to throw an invalid syntax exception, or heuristically return
      something reasonable.

    6. sdgathman commented on Jan 10, 2008

      sdgathmanmannequin
      Mannequin

      Repeating because previous real life test case was rejected as 'spam':

      It also fails to parse:
      >>> from email.Utils import parseaddr
      >>> parseaddr('foo@spammer.com <bar@baz.com>')
      ('', 'foo@spammer.com')

      Getting the wrong part as the actual email to boot! Checked 2.4 and 2.5.

    7. sdgathman commented on Jan 11, 2008

      sdgathmanmannequin
      Mannequin

      Same or related issues: bpo-1221, bpo-1409460

    8. sdgathman commented on Jan 11, 2008

      sdgathmanmannequin
      Mannequin
      Test cases so far:
        >>> parseaddr('user@example.com')
        ('', 'user@example.com')
        >>> parseaddr('"Full Name" <foo@example.com>')
        ('Full Name', 'foo@example.com')
        >>> parseaddr('spam@spammer.com <foo@example.com>')
        ('spam@spammer.com', 'foo@example.com')
        >>> parseaddr('God@heaven <@hop1.org,@hop2.net:jeff@spec.org>')
        ('God@heaven', 'jeff@spec.org')
        >>> parseaddr('Real Name ((comment)) <addr...@example.com>')
        ('Real Name', 'addr...@example.com')
        >>> parseaddr('a(WRONG)@b')
        ('', 'a@b')
    9. tiran commented on Jan 11, 2008

      @tiran
      Member

      An example from bpo-1221:

      >>> email.Utils.parseaddr("a(WRONG)@b")
      ('WRONG WRONG', 'a@b')
    10. sdgathman commented on Jan 11, 2008

      sdgathmanmannequin
      Mannequin

      tiran: yes, but that is the wrong answer, and that example is already in
      the testcase list (with what I believe is the right answer).

    11. removed their assignment
      on May 5, 2010
    12. 4 remaining items

    13. removed their assignment
      on May 16, 2012
    14. removed their assignment
      on May 16, 2012
    15. thehesiod commented on Sep 6, 2017

      thehesiodmannequin
      Mannequin
      from 3.6:
      >>> AddrlistClass('John Smith <john.smith(comment)@example.org>').getcomment()
      ''
      
      >>> AddrlistClass('John Smith <john.smith(comment)@example.org>').getdomain()
      'JohnSmith'

      totally messed up :)

    16. thehesiod commented on Sep 6, 2017

      thehesiodmannequin
      Mannequin

      looks like these were meant to be internal methods, retracting new issues

    17. transferred this issue fromon Apr 9, 2022
    18. added 2 commits that reference this issue on Aug 25, 2024
    19. added 4 commits that reference this issue on Aug 25, 2024
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

    Metadata

    Metadata

    Assignees

    No one assigned

      Labels

      stdlibStandard Library Python modules in the Lib/ directorytopic-emailtype-bugAn unexpected behavior, bug, or error

      Projects

      No projects

        Milestone

        No milestone

        Relationships

        None yet

        Development

        No branches or pull requests

        Issue actions