diff --git a/bleach/linkifier.py b/bleach/linkifier.py index 68a4042e..df56f3c3 100644 --- a/bleach/linkifier.py +++ b/bleach/linkifier.py @@ -1,5 +1,7 @@ import re +from urllib.parse import quote + from bleach import callbacks as linkify_callbacks from bleach import html5lib_shim @@ -298,10 +300,15 @@ def handle_email_addresses(self, src_iter): {"type": "Characters", "data": text[end : match.start()]} ) + # URL-encode the "local-part" according to RFC6068 + parts = match.group(0).split("@") + parts[0] = quote(parts[0]) + address = "@".join(parts) + # Run attributes through the callbacks to see what we # should do with this match attrs = { - (None, "href"): "mailto:%s" % match.group(0), + (None, "href"): "mailto:%s" % address, "_text": match.group(0), } attrs = self.apply_callbacks(attrs, True) diff --git a/tests/test_linkify.py b/tests/test_linkify.py index 69181ca2..fbabf122 100644 --- a/tests/test_linkify.py +++ b/tests/test_linkify.py @@ -104,6 +104,17 @@ def ft(attrs, new=False): ), # Incorrect email ('"\\\n"@opa.ru', True, '"\\\n"@opa.ru'), + # RFC6068 special characters + ( + "gorby%kremvax@example.com", + True, + 'gorby%kremvax@example.com', + ), + ( + "unlikely?address@example.com", + True, + 'unlikely?address@example.com', + ), ], ) def test_email_link(data, parse_email, expected): @@ -115,15 +126,15 @@ def test_email_link(data, parse_email, expected): [ ( '"james"@example.com', - """"james"@example.com""", + """"james"@example.com""", ), ( '"j\'ames"@example.com', - """"j'ames"@example.com""", + """"j'ames"@example.com""", ), ( '"ja>mes"@example.com', - """"ja>mes"@example.com""", + """"ja>mes"@example.com""", ), ], )