Repository: pydantic/pydantic
Issue category: Performance Issue

Issue:
Email parsing slowdown on edgecases
### Initial Checks

- [X] I confirm that I'm using Pydantic V2

### Description

I found that current pydantic-level regexp is not optimal and may cause unexpected slowdowns on some edgecases. Email strings like `<        ` (+many spaces). 

POC below shows it. You can run it  with command like `/usr/bin/time python pydantic-poc.py 500`.
The third value in a line should be near constant which shows that approximate complexity of one operation is ~ O(N^3)

I believe it is not a security issue because it runs fast enough even for largest possible sequences however.

### Example Code

```Python
import sys

from pydantic import BaseModel, EmailStr, ValidationError
import time


class TestModel(BaseModel):
    email: EmailStr


def main(max_ind: int):
    for ind in range(1, max_ind):
        begin_at = time.time()
        try:
            TestModel.parse_obj({"email": "<" + " " * ind})
        except ValidationError:
            pass
        delta = time.time() - begin_at
        print(
            f"{ind} takes: {delta:0.6f}, delta**1/3 / ind is {delta**(1/3) / ind:0.6f}"
        )
    return


if __name__ == "__main__":
    main(int(sys.argv[1]))
```


### Python, Pydantic & OS Version

```Text
pydantic version: 2.9.2
        pydantic-core version: 2.23.4
          pydantic-core build: profile=release pgo=false
                 install path: /home/alex/Projects/re-conference/venv/lib/python3.12/site-packages/pydantic
               python version: 3.12.3 (main, Sep 11 2024, 14:17:37) [GCC 13.2.0]
                     platform: Linux-6.8.0-45-generic-x86_64-with-glibc2.39
             related packages: typing_extensions-4.12.2
                       commit: unknown
```



Hints:

Patch:
diff --git a/pydantic/networks.py b/pydantic/networks.py
index 256f2bf1e4..a8ed1e248d 100644
--- a/pydantic/networks.py
+++ b/pydantic/networks.py
@@ -722,7 +722,7 @@ def _build_pretty_email_regex() -> re.Pattern[str]:
     name_chars = r'[\w!#$%&\'*+\-/=?^_`{|}~]'
     unquoted_name_group = rf'((?:{name_chars}+\s+)*{name_chars}+)'
     quoted_name_group = r'"((?:[^"]|\")+)"'
-    email_group = r'<\s*(.+)\s*>'
+    email_group = r'<(.+)>'
     return re.compile(rf'\s*(?:{unquoted_name_group}|{quoted_name_group})?\s*{email_group}\s*')
 
 


Test patch:
diff --git a/tests/test_networks.py b/tests/test_networks.py
index f576705473..3ac7204e96 100644
--- a/tests/test_networks.py
+++ b/tests/test_networks.py
@@ -908,6 +908,8 @@ class Model(BaseModel):
         ('FOO bar   <foobar@example.com> ', 'FOO bar', 'foobar@example.com'),
         (' Whatever <foobar@example.com>', 'Whatever', 'foobar@example.com'),
         ('Whatever < foobar@example.com>', 'Whatever', 'foobar@example.com'),
+        ('Whatever <foobar@example.com >', 'Whatever', 'foobar@example.com'),
+        ('Whatever < foobar@example.com >', 'Whatever', 'foobar@example.com'),
         ('<FOOBAR@example.com> ', 'FOOBAR', 'FOOBAR@example.com'),
         ('ñoñó@example.com', 'ñoñó', 'ñoñó@example.com'),
         ('我買@example.com', '我買', '我買@example.com'),