mailto: and the Problem with Silent Failure
In systems engineering, there is a principle that is often overlooked: when something fails, it should be evident. A request that simply vanishes is worse than a 500 error. Undefined behavior is worse than a compile error. A timeout is better than a hang. It's much more difficult to determine what's wrong when you can't see it, but you can fix what you can see. ( Kinda why a lot of vibe coded apps fail )
mailto: is a case study in such behavior. A case study of this kind of behavior is mailto.
It has been in HTML since 1994, is technically 'fine', passes all linters, but for a significant
portion of users, nothing happens and there is no sign that something went wrong when it is referenced by the browser.
I want to discuss why that occurs, why AI continues to produce it, and what the alternative looks like when you reason from what Aristotle called archai, first principles. 1
What mailto: Actually Is
mailto: is not an HTML tag. It is an IETF-defined URI scheme, similar to https: or ftp:. It was formalized in RFC 1738 in December 1994, expanded in RFC 2368 (July 1998), and received its final revision in RFC 6068 (October 2010).2
Most people are unaware of how much the scheme can do. The subject, body, CC, and BCC can all be pre-filled and encoded into the URL:
An anchor tag can contain basically an entire email draft.
Opaque Delegation
A browser does not process the request itself when it comes across mailto:.
It transfers control to the operating system, which searches for the program that has been designated as the mailto: protocol's default handler. Said program opens if it is installed and set up but
if not, the url header is displayed on a blank page and no redirect occurs.
Using this scheme opens up a black box that the developer has no access to. In this black box are a series of systems such as the OS default app settings, the protocol handler registry in the browser, and the status of any installed email client. Has the email client opened? Was the message sent by the user? Did they come to a standstill? You have no idea.

However, in 1994, this transfer of control was pretty sure fire since most people had
a pre-configured email client. But about a decade later, Gmail launched in 2004, and
with it emails moved into the browser. But browsers cannot handle mailto: innately since it relies
on OS-level protocol registrations. If the user does all their email in a
Chrome tab and never configured a handler, clicking mailto: either opens an Apple Mail setup wizard, triggers a Windows Store prompt, or
does nothing.
Even on macOS, where Apple Mail ships pre-installed, the UX is pretty bad when it comes to changing the default mail handler.
To change the default mail handler, you have to open Mail, go to Settings, and
pick a different app from the dropdown. Except the Settings menu is greyed
out unless you have already configured an email account in Mail. To tell
macOS you do not want to use Apple Mail, you first have to set up Apple
Mail.3 The
terminal workaround that power users relied on
(LSSetDefaultHandlerForURLScheme) was deprecated in macOS 14.2.
This has not changed through Sequoia or Tahoe.
In addition to this, Chrome can be set as the default mail handler, and it cannot handle mailto: links.
Apple apparently considers this acceptable.
There is no onerror callback for a mailto: click
so there is no programmatic way to determine whether it succeeded.
In any other context we would call this an unobservable failure mode and
treat it as a bug.
Exposed by Design
Another problem with mailto: links is that they publish your email
address in the DOM in a format specifically designed to be machine-readable.
The href says mailto:you@example.com. Bots have been harvesting
these with trivial regex(es?i?) since the late '90s.
In its security considerations, RFC 6068 recognizes the fact that mailto constructs can be located within HTML pages by automated means (even bcc'ed ones) and that addresses harvested this way are likely to end up on spam lists. The spec even acknowledges that sophisticated bots can get around obfuscation, which is a mentioned defence.4 An RFC hedging against a flaw in its pretty noteworthy.
You can do a bit of obfuscation by encoding characters as HTML entities, reconstructing the address in JavaScript at runtime, and splitting it across data attributes. Some of these reduce harvest rates but they are workarounds for a property of the scheme itself. It was built to be machine-readable. That is a feature for email clients and a vulnerability for developers.
Why AI Keeps Generating It
Ask a language model to build a contact page and there is a strong chance you
get mailto:.
LLMs learn to write code by reading code, and mailto: is heavily present within
the training corpus. It appears in every introductory HTML tutorial, in MDN
docs, in Stack Overflow answers, in W3Schools, in the source of millions of
archived websites. If you estimated the probability distribution over HTML
patterns following the phrase "contact us," mailto: is extremely likely to follow.
It has been the canonical answer to that question for 30 years. And this is one of the instances where
the most probable solution doesn't make the cut and LLM's will fall short.
There is also a bias toward 'simpler' solutions such as mailto: which is a singular line of code. A language model gravitating toward the simplest
complete answer will pick the mailto: token whenever it pops up. And the output is technically
correct as it is valid HTML and by all formal metrics available in the training data, it is good code.
This is not unique to mailto:. You see the same dynamic in
AI-generated code that reaches for deprecated APIs or patterns that were best
practice five years ago
Choosing How Things Break
There is no single HTML construct that opens an email compose window in every user's preferred client. Every approach to contact on the web makes an assumption about the user's environment. The engineering question is not which assumption is universally right, but what happens when the assumption is wrong.
mailto: has no ways to poll for the outcome. A direct compose link, like Gmail's mail.google.com/mail/?view=cm&fs=1&to=you@example.com, is a
standard https:// URL which will mostly load and if not, it will show an error.
It assumes the user has Gmail, which initially appears to be a very broad (but pretty probable)assumption.
But at least when that assumption is wrong, the user
lands on a login page and they see what happened. They can go back, or log in,
or try something else. The failure is explicit.
A plain-text email address on a webpage makes no assumptions. The user has the ability to view, copy, and paste it into any application. It is incredibly portable but the user bears the expense of doing the work themselves.
On this very site, I link the words "reach out" to a Gmail compose URL and display my email address as visible, copyable text. The link cannot silently fail. And anyone who does not use Gmail can see the address and handle it however they prefer. Every instance mailto: fumbles is covered by these two HTML tags.
This is not a solution that works every time. Rather, it is a conscious decision about which assumption to make and how to respond when that assumption is violated. And that is what engineering actually is: not only building things that never fail, but building things that fail in ways you can see, reason about, and overcome.
mailto: fails in ways you cannot see which is why I do not use
it, and why it is the first thing I check when an AI builds a contact page.
Feel free to "reach out" with any thoughts or questions about this essay, they will be very appreciated !
1. Aristotle, Physics I.1 (184a10): "We do not think that we know a thing until we are acquainted with its primary conditions or first principles, and have carried our analysis as far as its simplest elements." The term archai recurs throughout the Metaphysics (981b28) as the starting points from which all other knowledge is derived.
2. RFC 1738 defined the basic mailto: syntax. RFC 2368 added
query parameters for subject, body, CC, and BCC. RFC 6068, the current
standard, added internationalization and IRI compatibility. Jamie Zawinski
is a named author on both RFC 2368 and RFC 6068.
3. LSSetDefaultHandlerForURLScheme in Apple's LaunchServices
framework was deprecated in macOS 14.2.1 (Sonoma). As of Tahoe 26.0, the
only supported method is Mail.app's Settings panel, which requires an
active account configured in Mail. This Catch-22 has persisted unchanged
since at least macOS Ventura.
4. See Section 7 ("Security Considerations") of RFC 6068.