23

I have a website with a client-side HTML contact form created manually (not as output of an HTML constructor like PHP):

<form action="mailto:someone@example.com">
    Email Adress:<br>
    <input type="email" name="email_address" value="" maxlength="100" />
    <br>
    <input type="submit" value="Submit" />
</form>

I would like to hide that mailto:someone@example.com from all HTML source codes that include it, so that users would not be able to find the email address even in source code directly;
This way, generally only customers who have sent me an email and got a reply --- would know the email address (unless the user undid the hiding operation).

Is there a way to hide HTML source code yet keeping it effective?

Update

From reading all answers calmly, it seems my question had a false assumption: I missed big time that mailto will always eventually show the email as is in a user's email client pop up (and maybe also before that in preview in the bottom-left edge of the browser screen port); I think I missed that because a cognitive bias of the combination of replies suggesting source code obfuscation and an redundant-in-my-opinion sentence such as The question doesn't even make sense on a conceptual level; which I tried to remove in an edit (which was partially approved, sadly). I now understand that whatever I'll do, no matter how I'll obfuscate the source code; the email I putted in mailto will always eventually appear in a user emails client applied to a browser (if there is one - if not, there would just be no email sending effect).

  • 62
    there is just no way of hiding anything client side in html or javascript.Sure you could obfuscate it but at the end you can just intercept it and look at it – Vipul Nair Sep 19 at 11:04
  • 7
    @JohnDoea Hide it from whom? Certainly not the person sending the mail, as they'll see it anyway. The usual form of defeating dumb obfuscation is doing the opposite, and hiding the actual address in JS, which'll defeat scrapers that don't interpret the sides JS at the cost of making the links unusable for users that browse with JS disabled. But you can't simultaneously hide the address from end users and make it usable for end users, because these two goals are internally contradictory. – Cubic Sep 19 at 14:17
  • 41
    @JohnDoea OK the problem here is that you apparently don't know how mailto works. It's just a way to tell a user where they can send email to (and possibly set some default options like titles/cc and what not). The client is 100% in control of how to interpret this information. You might as well ask how to keep a cake after eating it. – Cubic Sep 19 at 14:23
  • 37
    Read about how mailto works and try the Try it Yourself button. No matter how you obfuscate the address, it will open the user's mail client where the address is shown in plain text. – JollyJoker Sep 19 at 19:16
  • 30
    This is an obvious XY problem What issue are you really trying to solve @JohnDoea – Doryx Sep 19 at 23:14

12 Answers 12

54

You can't. The question doesn't even make sense on a conceptual level. A mailto: link is simply a convenient way to communicate to an end user where they can send email to. If your mailto link works, the end user will by definition know where the email is going to, the same way the end user will by definition know where a link they're clicking will be going to.

You'll have to ask yourself what problem you're trying to solve; if you want to hide the name of recipients you can do this by creating obscured or even temporary email addresses on your mail server and forwarding mail to the actual recipients from those, in a similar way to how URL shorteners can be used to obscure the actual destination of a link, but a user will always see the the email address they're sending to because that's just how email works.

  • 8
    Well, the question only "doesn't even make sense" if you know basically how mailto: links work and refuse to think about impossible things. It's a question about how to do something impossible, but such questions aren't necessarily nonsense. – Brilliand Sep 19 at 21:14
  • 2
    @Brilland The problem presented here isn't impossible because of technological limitations but because it doesn't make conceptual sense. Hiding information from the user they need to do something you want them to do is conceptually impossible. – Voo Sep 20 at 7:43
  • 5
    @Brilliand The question is definitely nonsense, but the underlying problem may not be, which is why there's a second paragraph addressing what I think might be the actual problem OP is trying to solve. – Cubic Sep 20 at 8:52
  • 6
    @JohnDoea The server-side solution is completely different because it basically just involves the user not sending email at all. You (as in, your server) are the only one sending any emails under these circumstances. This is obviously a possible Y to the XY problem you presented here. But the second you actually require the user to send any mail themselves they'll need to know where to send the mail to (again, because that's just how email works, see en.wikipedia.org/wiki/Simple_Mail_Transfer_Protocol for instance) – Cubic Sep 20 at 13:39
  • 1
    @John Encoding and encryption won't help you either. You're literally triggering the user's email program. The email program will display and store, as it does for any other outgoing email, the target address. It has to know that address otherwise it won't know where to send the email. It is fundamentally nonsense to hide that in any way whatsoever while the client is sending the email. Period. Full stop. – Lightness Races with Monica Sep 21 at 14:53
129

You cannot hide HTML and expect the browser to be able to interpret it. The browser needs full access to the HTML in order to display all parts of the site. As soon as the browser has access to it, the user can also gain access to it.

On a further note, JavaScript is also not able to "hide" the content of the site and still make it accessible to the browser, and thus the end user, for the exact same reason.

  • 31
    You could add a sentence to explain that in order to hide the email address, you need to process the request server-side, to solve both of the problems OP is presenting – Mars Sep 20 at 0:19
  • @JohnDoea In general code could be run through an obfuscator that replaces all the variable names to long random strings, deletes all non-required white-space, line-breaks, and comments, and overall makes the code extremely unreadable even if it can be viewed. This of course doesn't prevent a determined party analyzing the code, but it will drastically increase the time it takes them to figure out what the code does. For this simple email case, it may not be effective though. – user4574 Sep 20 at 17:35
  • 3
    @user4574 Not necessarily. All I am interested in is the e-mail address, which is essentially a string. It must end up in plaintext at some point, and I can just debug and step through the code without caring what it does, until the address pops up. – MechMK1 Sep 20 at 18:09
  • 1
    "You cannot hide HTML and expect the browser to be able to interpret it." clearly you have never viewed the source for samy.pl – exussum Sep 20 at 22:14
  • 1
    @MechMK1 Yes but all security defences are ultimately built on trade-offs of one kind or another. It depends on what you're trying to accomplish and how weak an attack you find it worthwhile to prevent. Obfuscation may be acceptable, particularly obfuscation to the level of samy.pl's. Of course the HTML is irrelevant anyway as the form just pops up the user's email client :D – Lightness Races with Monica Sep 21 at 14:49
101

Well, IMHO the only reliable way to prevent the user to know the mail address it to have the mail sent server side instead of client side. Said differently the client only gives their own mail address and the text, it is uploaded to the server by the form, and the mail is sent by the server application which is the only part knowing the recipient address.

This is commonly used in help centers to prevent users to directly use their internal addresses.

  • 4
    While this solves the Y problem "How can I receive emails without disclosing the recipient address?", I don't think this actually solves the X question asked in the title. – MechMK1 Sep 19 at 13:33
  • 1
    This is commonly used in help centers to prevent users to directly use their internal addresses. this part specifically wasn't clear to me... – JohnDoea Sep 19 at 14:23
  • 15
    @MechMK1: your answer already addressed the hiding part, so I proposed a different approach... – Serge Ballesta Sep 19 at 14:31
  • 6
    @JohnDoea: when I want to ask a question to the help desk of my ISP, I get a page where I can write a full message. I the receive the response in my mail, but I have no way to send the message from Thunderbird, because I have no way to guess what address I could use (and of course the sender address used in response is blocked...) – Serge Ballesta Sep 19 at 14:35
  • @MechMK1 The question in the title is malformed, as Javascript cannot hide source code. Server-side rendering and logic does. – The Anathema Sep 20 at 1:24
16

You can't. And neither can Javascript. You have three options, and they all depend on a backend language. You have two options, one right way and two lunatic ways if you have no server:

The right way: You do a form submit to a server, and the server handles this e-mail over SMTP.

The okay way: You submit to another domain or API that can handle it server-side.

The crazy way: You write a desktop application that is registered to your own custom URL protocol and the parameters include the form's body. Your consumer installs this desktop application, and it silently handles this e-mail over SMTP instead of opening their e-mail client. The destination mail can be hardcoded within that application and they can't get it unless they decompile or do a memory dump. Instead of "mailto:email.com" it becomes "custom-mail:" sans the mail.

This is what "mailto" is. It's a protocol that's registered with the OS. However, keep in mind that if you're relying on their client and "mailto", it doesn't matter what you do. They'll see it the second their client opens, so you didn't really solve anything here.

  • 2
    For your option #3, although it's clearly not meant in a serious manner: They don't even have to decompile or use a memory dump (or run strings on the executable). All they have to do is to sniff the outgoing traffic and see to what servers the application connects. You can do that on Windows out of the box. – Voo Sep 20 at 10:30
  • @Voo This is true, but the same is true for everything except code executed on servers that the client cannot connect to in any way. – The Anathema Sep 20 at 19:35
  • 2
    Absolutely. It just drives home the futility of trying to hide local information. – Voo Sep 20 at 21:13
  • @Voo I would hope that that outgoing connection is encrypted. – Paŭlo Ebermann Sep 22 at 1:58
  • 1
    I thought about something like STARTTLS or SMTPS, which both wrap the content of almost the whole SMTP connection into a TLS connection – one is integrated into SMTP, one is just wrapped around (and uses a different port). You won't hide your server's domain name (or IP address) this way, but certainly the email address itself from any network observation. (Of course, you still have the program code which you can decompile, or run in a debugger. White box crypto might help here.) – Paŭlo Ebermann Sep 22 at 8:54
12

You can HTML-encode it, like this:

<form action="&#x6d;&#x61;&#x69;&#x6c;&#x74;&#x6f;&#x3a;&#x73;&#x6f;&#x6d;&#x65;&#x6f;&#x6e;&#x65;&#x40;&#x65;&#x78;&#x61;&#x6d;&#x70;&#x6c;&#x65;&#x2e;&#x63;&#x6f;&#x6d;">

However, that only really obfuscates it. Anyone can decode this.

If you really want to hide it you need server side functionality (PHP), where the form is submitted to the server and the server emails it to you.

  • 11
    Minor nitpick: while this would mildly obfuscate it in source code, it would be visible in plain-text version to anyone who looked in the browser console. As a result, it's worth emphasizing that even this level of obfuscation is incredibly easy for any user to work around – Conor Mancone Sep 19 at 11:18
  • 4
    @ConorMancone Yes, but lazily written scrappers or script kiddies won't think about doing all the legwork to try to decode the HTML entities. – Ismael Miguel Sep 20 at 9:11
  • 1
    It doesn't solve the problem for a targeted attack, but I might start implementing this in a lot of forms."It's something ¯\_(ツ)_/¯" – TCooper Sep 20 at 18:26
  • 1
    @TCooper (a) The OP isn't trying to protect against scrapers - this does literally nothing to achieve the goal (b) Scrapers have been getting around this trick for decades – Lightness Races with Monica Sep 23 at 17:45
  • 1
    There is no potential benefit and the harm is it's harder to implement and maintain. – Lightness Races with Monica Sep 23 at 23:53
7

To accomplish what you're trying to do, get a gmail address or forwarding address that you use in your form, which serves your purpose of keeping your real email address secret.

  • Given that the asker still plans to study server side operations later and just needs to let people mail without exposing the address, this seems like a pragmatic solution to preserve privacy. Though I suppose this would still allow people to send messages by email as they would get redirected... – Dennis Jaheruddin Sep 21 at 18:35
  • Along with this I often use International email: Gmail supports it, but not many regular expressions, so things like example+ツ@gmail.com are often ignored. A human may remove the part after the plus if their server don't support that, in the other hand a bot might not even consider it a valid address or recognize that as just @gmail.com. – Gustavo Rodrigues Sep 21 at 19:29
7

TL;DR: No.

If I understand your problem correctly, you do not want to hide the e-mail address from the users, but from bots which parse the source code to collect e-mail addresses for spamming.

Sure, in JavaScript there are several easy ways reduce to this problem to practically zero, because it needs execution of the script which hardly any spammer does:

function getEMailAddr(user, domain) {
   return user + '@' + domain;
}

and then:

link = document.createElement('A');
link.href = 'mailto:' + getEMailAddr('example', 'something.com');

In plain HTML, there is no way to do this. However, there are some possibilities to make less attack surface for stupid parsers. The very catchy at-sign can be expressed as HTML entities &at; or &#64;, so that parsers that only search for @ fail to find them. These HTML entities are also allowed in attribute values, such as href.

  • 2
    Actually Google executes the javascript. I've seen spammers crawl a site, Google the page with the obfuscation and simply parse the resulting page. – P. Goetterup Sep 20 at 9:55
  • @P.Goetterup What you describe is no longer a stupid parser, because it has to perform the Google lookup. – rexkogitans Sep 20 at 10:04
  • There are tons of more proper HTML + JS obfuscators. If you're going to use obfuscation, I recommend picking a standard obfuscator, which often makes it a whole lot more difficult than this half-obfuscation for someone to get that mail address (while still very much possible, though). – Erik A Sep 20 at 10:23
  • @rexkogitans it's hardly "not stupid". All you need is to execute the page, instead of using the equivalent of wget to fetch the source. There are plenty of bots that are piggybacking on tools like Selenium that use a browser to fetch and manipulate a page as it would appear to a user. It's about as simple to use such a bot as one that does static HTML parsing. In the end, the bot (and the code you write for it) doesn't really need much sophistication to - a regex for the email would work for both. – VLAZ Sep 20 at 12:53
  • @VLAZ that is the other face of the 'automated testing' medal ;P – beppe9000 Sep 20 at 22:33
5

You can't hide HTML from the browser. HTML is a client-side markup language which means that it is loaded by the browser on the client-side, so the browser must be able to interpret it.

As someone alluded to, you won't be able to accomplish what you're trying to accomplish with the way that you are doing it. You might be able to accomplish something close by encoding/decoding elements as needed, however, security through obscurity is not a recommended strategy, and anyone can easily decode an encoded string.

4

Alternative answer.

Yes there is, try and view the source of https://samy.pl/ its almost impossible to find, you have to be pretty dedicated to find it yet the website works fine.

But more seriously the code is still visible, Its just out of reach of most users, even those who have some idea of where to look.

HTML/JS is all executed client side, so it's impossible not to give it to the client to process.

The part you specifically wish to hide actually triggers in the client browser, a mailto link is a link telling the computer to open a mail client and pre fill in the form. So even if you did do what Samy does, clicking the link will simply open in the mail client and show the end user the email address.

If you wish to keep it secret, email must be sent server side

  • That is wild. I have no idea how he did that. – The Anathema Sep 20 at 22:39
  • Actually I had no trouble figuring that one out, after a couple of minutes. Yeah, it's good, but it is decipherable. Now, good luck trying to understand what the home page to Google.com is doing! – Marc.2377 Sep 22 at 4:07
2

As others have said, you can't hide HTML. However it sounds like you don't particularly want to hide HTML, you just want the recipient of the form to not be visible in your code which is simple enough depending on your framework.

For example, if you're using PHP, PHP Mailer is a pretty simple way to send an email, and since PHP is handled server side, when your form submits the user won't ever see your email address if you don't want them too.

If you're using ASP.NET or whatever else, simply typing the name of your environment and email into your favorite search engine will likely give you plenty of options on how to send an email and you can combine that with your form to do it server side.

2

TL;DR: No, you can't hide the HTML source code. You can only obfuscate the email address to defer spammers as long as you don't use server side code.

Besides using HTML entities (&#x6d;) or Javascript, you can also use XSLT for obfuscation, if you use XHTML instead of HTML.

XSLT is a XML-based programming language supported by all major browsers that can transform any XML into another form (XML, HTML, Plaintext, etc.). One application would be to pass through most of the document except for action attributes that contain a magic part, e.g. +rot13.

One advantage is that this also works in browsers where Javascript is disabled. One caveat is that you need to write XHTML, so instead of the lenient HTML parser browsers use the strict XML parser, which causes error messages on every syntax error.

Please also keep in mind that every HTML obfuscation technique can only defer spammers. The browser needs the correct mailto link to do the right thing when submitting the form, so eventually the user will see the unobfuscated address.

index.xhtml

<?xml-stylesheet type="text/xsl" href="obfuscation.xsl" ?>
…
<form action="mailto+rot13:fbzrbar$rknzcyr.pbz">
    Email Adress:<br/>
    <input type="email" name="email_address" value="" maxlength="100" />
    <br/>
    <input type="submit" value="Submit" />
</form>

obfuscation.xsl

<xsl:stylesheet
    version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:html="http://www.w3.org/1999/xhtml">
<xsl:output method="xml" encoding="UTF-8"/>

<!-- Identity Transformation for HTML nodes -->
<xsl:template match="@*|html:*">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()" />
    </xsl:copy>
</xsl:template>

<!-- decode form actions with a ROT-13 variant  -->
<xsl:template match="@action[contains(substring(., 0, 16), '+rot13:')]">
    <xsl:attribute name="action"><xsl:value-of select="substring-before(., '+')"/>:<xsl:value-of select="translate(substring-after(., ':'),'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@$6789012345', 'NOPQRSTUVWXYZABCDEFGHIJKLMnopqrstuvwxyzabcdefghijklm$@1234567890')" /></xsl:attribute>
</xsl:template>

</xsl:stylesheet>
  • 1
    I was happy to learn of XSLT and more from your answer, upvoted. Thank you, – JohnDoea Sep 22 at 20:17
2

This cannot be done for a mailto link, however there are services like MailThis, Formspree, that allows you to build a form that posts to their server, and they'll convert that to send an email. MailThis also allows you to create an alias name so that you don't expose your real email address on the HTML page itself.

Not the answer you're looking for? Browse other questions tagged or ask your own question.