Repository: mkdocs/mkdocs

Issue:
Mailto links not correctly interpreted
Hi, 
I've noticed "mailto" links are not correctly interpreted.
- This code:

```
Contact us at <foo@bar>
```
- Renders the following link:  
  http://localhost//mailto:foo@bar  

---
- This code:

```
You can [contact us](foo@bar)
```
- Renders the following link:  
  http://localhost/page/permalink/foo@bar



Discussion:
The first issue is a bug in MkDocs. The second is user error. See below for details.

This is caused by the relative path extension to Python-Markdown which ships with MkDocs. The extension attempts to "do the right thing" and [return immediately](https://github.com/mkdocs/mkdocs/blob/master/mkdocs/relative_path_ext.py#L66) if a scheme is included in the URL. However, the Markdown's [Syntax Rules](https://daringfireball.net/projects/markdown/syntax#autolink) require email addresses to be entity-encoded and Python's `urlparse` function does not understand the encoded url properly (browsers do so this is only a problem when using `urlparse`):

``` python
>>> from mkdocs.utils import urlparse
>>> urlparse("mailto:foo@bar")
ParseResult(scheme='mailto', netloc='', path='foo@bar', params='', query='', fragment='')
>>> urlparse("&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#102;&#111;&#111;&#64;&#98;&#97;&#114;")
ParseResult(scheme='', netloc='', path='&', params='', query='', fragment='109;&#97;&#105;&#108;&#116;&#111;&#58;&#102;&#111;&#111;&#64;&#98;&#97;&#114;')
```

As this only happens with email autolinks, perhaps the extension could check for the encoded "mailto" scheme:

``` python
if scheme or netloc or not path or url.startswith('&#109;&#97;&#105;&#108;&#116;&#111;&#58;'):
    return url
```

As stated above, the encoding only applies to autolinks (links surrounded by `<anglebrackets>`). Therefore, regular links to not get encoded and this is not an issue.

The second example is user error as that is not valid Markdown. When defining any absolute address (web or email) for a link, you need to define the scheme (`http:`, `https:`, `ftp:`, `mailto:`, etc.), including for email addresses. Like this:

```
You can [contact us](mailto:foo@bar)
```

In fact, most (all?) Markdown parsers require the scheme (see Babelmark: [with](http://johnmacfarlane.net/babelmark2/?normalize=1&text=You+can+%5Bcontact+us%5D%28mailto%3Afoo%40bar.com%29), [without](http://johnmacfarlane.net/babelmark2/?normalize=1&text=You+can+%5Bcontact+us%5D%28foo%40bar%29)). It is not added automatically unless you use an autolink. In fact, many parsers [fail](http://johnmacfarlane.net/babelmark2/?normalize=1&text=Contact+us+at+%3Cfoo%40bar%3E) there as `foo@bar` is not considered a valid email address (Python-Markdown is actually pretty loose about what it considers an email address so its not a problem for us). However, `foo@bar.com` [works fine](http://johnmacfarlane.net/babelmark2/?normalize=1&text=Contact+us+at+%3Cfoo%40bar.com%3E) for everyone.


Resolving patch:
diff --git a/mkdocs/relative_path_ext.py b/mkdocs/relative_path_ext.py
--- a/mkdocs/relative_path_ext.py
+++ b/mkdocs/relative_path_ext.py
@@ -43,6 +43,7 @@
 
 from markdown.extensions import Extension
 from markdown.treeprocessors import Treeprocessor
+from markdown.util import AMP_SUBSTITUTE
 
 from mkdocs import utils
 from mkdocs.exceptions import MarkdownNotFound
@@ -61,8 +62,10 @@ def path_to_url(url, nav, strict):
     scheme, netloc, path, params, query, fragment = (
         utils.urlparse(url))
 
-    if scheme or netloc or not path:
+    if scheme or netloc or not path or AMP_SUBSTITUTE in url:
         # Ignore URLs unless they are a relative link to a markdown file.
+        # AMP_SUBSTITUTE is used internally by Markdown only for email,which is
+        # not a relative link. As urlparse errors on them, skip explicitly
         return url
 
     if nav and not utils.is_markdown_file(path):


Test patch:
diff --git a/mkdocs/tests/build_tests.py b/mkdocs/tests/build_tests.py
--- a/mkdocs/tests/build_tests.py
+++ b/mkdocs/tests/build_tests.py
@@ -196,6 +196,18 @@ def test_not_use_directory_urls(self):
         html, toc, meta = build.convert_markdown(md_text, load_config(), site_navigation=site_navigation)
         self.assertEqual(html.strip(), expected.strip())
 
+    def test_ignore_email_links(self):
+        md_text = 'A <autolink@example.com> and an [link](mailto:example@example.com).'
+        expected = ''.join([
+            '<p>A <a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#97;&#117;&#116;',
+            '&#111;&#108;&#105;&#110;&#107;&#64;&#101;&#120;&#97;&#109;&#112;&#108;',
+            '&#101;&#46;&#99;&#111;&#109;">&#97;&#117;&#116;&#111;&#108;&#105;&#110;',
+            '&#107;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;',
+            '</a> and an <a href="mailto:example@example.com">link</a>.</p>'
+        ])
+        html, toc, meta = build.convert_markdown(md_text, load_config())
+        self.assertEqual(html.strip(), expected.strip())
+
     def test_markdown_table_extension(self):
         """
         Ensure that the table extension is supported.