Rendering an HTML link across Gmail, Outlook, and iCloud mail
I came across an interesting bug inconsistency recently that had me scratching my head. A client of mine wanted his web application to send emails to users. The body of the email would contain links.
Simple enough I thought. I’ve done this before. I’ll use Mailgun’s API and send raw HTML in the payload. I did exactly that and then we started testing. We had the web application send an email to a Gmail account and it rendered as follows:
OK great. And the link works too. We did the same with an iCloud account and something funny happened:
That’s just text. Strange. We did the same again with an Outlook account and something funny happened again:
Uhh OK. Almost looks like markdown.
My first thought was maybe the receiving mail server was changing the message’s source code. I checked and the source was the same across all three clients. I went back to my backend code and checked exactly what I was sending out:
domain = "example.com"
url = domain + "/building/show/" + str(building.id)
email_text = "<html><head></head><body><a href='" + url + "'/>Camille Rouge Apartments</a></body></html>"
api_call_to_mailgun(email_text, ...)
Hmm. Let’s see how the link gets rendered in each of the three web clients. I went to each and inspected the link element. Gmail gave me:
<a href="http://example.com/building/show/123" target="_blank">Camille Rouge Apartments</a>
Interesting. Gmail’s client injected the “http://” prefix into the href
attribute. And what did Outlook do?
[example.com/building/show/123]Camille Rouge Apartments
That is plain text. Outlook drops the <a>
tag altogether. And iCloud mail?
<a>Camille Rouge Apartments</a>
Am I sending out non-compliant HTML? I went over to the W3C HTML validator and checked:
Nope. What is going on? Well, we know the link works in Gmail and we also know it is injecting the protocol prefix. Let’s try putting in the prefix ourselves:
domain = "https://example.com"
url = ...
email_text = ...
api_call_to_mailgun(email_text, ...)
And that actually works across all three clients! Looks like the iCloud and Outlook clients are picky.
Moral of the story: include the “http[s]” prefix in your href
attributes. Hope that saves someone out there some unnecessary head scratching.
Edit 12/24 - mini HN discussion about the cause here. Turns out if you leave out the prefix, the link gets treated as a relative path which I’m guessing Outlook & iCloud bet against and throw out the link altogether.