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 – yeah_well Sep 19 '19 at 11:04
  • 1
    What is the expected outcome? Should the mailto work in the end, but you want to hide the recipient? There are better ways to do that... – Marcel Sep 19 '19 at 11:22
  • 2
    @Marcel, yes, `mailto` should work while I hide its address to hide the recipient... That's all... –  Sep 19 '19 at 11:28
  • 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 '19 at 14:17
  • @Cubic they'll surly see it if they send email and I reply but if I don't and it's hidden from `mailto:` somehow, how could they see it if they send email and I didn't reply? –  Sep 19 '19 at 14:20
  • 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 '19 at 14:23
  • 1
    Do it with JavaScript and use a ` – user875234 Sep 19 '19 at 19:08
  • 37
    [Read about how mailto works](https://www.w3docs.com/snippets/html/how-to-create-mailto-forms.html) 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 '19 at 19:16
  • 30
    This is an obvious [XY problem](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem) What issue are you really trying to solve @JohnDoea – Doryx Sep 19 '19 at 23:14
  • What are you trying to avoid by hiding the email address? If people can spam you using the form, they can spam you. – Džuris Sep 20 '19 at 10:52
  • 1
    @Džuris as absurd as it sounds I just want to hide the email so people won't search it in Google - yes, I can open another email account but I have 2 already and it's already heavy on me mentally --- maybe I need a psychologist, or some medical cannabis. –  Sep 20 '19 at 10:54
  • 1
    @JohnDoea no, you just need an email client like thunderbird or outlook where you receive all the emails instead of visiting individual webmails. Then it's no problem if you have an actual mailbox for your every website. – Džuris Sep 20 '19 at 11:12
  • 1
    The dumb way to "hide" an address from web scrapers is to just show it in HTML as `emailmail.com` - make some part it an image. The `@` is the easiest, since it's flexible to what you can put before and after but you can also make `@mail.com` into an image. Web scrapers tend to just search for straight email looking thing in the HTML, so an image will throw them off. Makes it annoying for users, though, as they can't copy/paste the thing any more. – VLAZ Sep 20 '19 at 11:39
  • 1
    If you only want to hide it from a normal google-search or site-crawler, you can do so easily with JavaScript. Just create the page with an empty mail:to and write a JS-Method, which will fill in the email-address with something like btoa('base64-encoded-adress') when the user inputs something into the contact form – Falco Sep 20 '19 at 15:13

12 Answers12

127

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 '19 at 00: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 '19 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. –  Sep 20 '19 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 '19 at 22:14
  • @exussum All anti-debugging steps are essentially just another form of obfuscation. –  Sep 21 '19 at 09:18
  • 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 in Orbit Sep 21 '19 at 14:49
  • @MechMK1 too complex. If I know it's a mailto: action, I just submit the form and read the address off my mail client. – John Dvorak Sep 21 '19 at 20:09
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.

Serge Ballesta
  • 25,636
  • 4
  • 42
  • 84
  • 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. –  Sep 19 '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... –  Sep 19 '19 at 14:23
  • 15
    @MechMK1: your answer already addressed the *hiding* part, so I proposed a different approach... – Serge Ballesta Sep 19 '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 '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 '19 at 01:24
  • @SergeBallesta I would expect most such systems to connect to a ticketing system and not to send emails to the help center workers (though the ticketing system would no doubt have some notification system that could send emails). While there are certainly many reason to keep internal email addresses out of end-user interactions, this seems more like a side-effect of using a ticketing system rather than a motivation for it. – Derek Elkins left SE Sep 20 '19 at 04:41
  • All ticketing systems I know offer an input mail connector, but most help desk system do not activate it. They have a greater control with what is sent through their web application than through the client mailler. – Serge Ballesta Sep 21 '19 at 08:54
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.

Cubic
  • 626
  • 5
  • 7
  • 9
    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 '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 '19 at 07: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 '19 at 08: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 https://en.wikipedia.org/wiki/Simple_Mail_Transfer_Protocol for instance) – Cubic Sep 20 '19 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 in Orbit Sep 21 '19 at 14:53
  • 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). –  Sep 22 '19 at 20:43
15

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.

The Anathema
  • 251
  • 1
  • 4
  • 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 '19 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 '19 at 19:35
  • 2
    Absolutely. It just drives home the futility of trying to hide local information. – Voo Sep 20 '19 at 21:13
  • @Voo I would hope that that outgoing connection is encrypted. – Paŭlo Ebermann Sep 22 '19 at 01:58
  • @Paŭlo Which SMTP extension supports encrypting email addresses? I mean you can encrypt the content of emails (and goodness is that a PITA) but the actual address? – Voo Sep 22 '19 at 07:52
  • 1
    I thought about something like [STARTTLS](https://en.wikipedia.org/wiki/STARTTLS) or [SMTPS](https://en.wikipedia.org/wiki/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 '19 at 08:54
  • @Paŭlo Ah I was more thinking about PGP and co. But true, STARTTLS would help if you didn't want to play any downgrade games (which definitely wouldn't be that easy) – Voo Sep 22 '19 at 20:34
11

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.

Sjoerd
  • 28,707
  • 12
  • 74
  • 102
  • 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 '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 '19 at 09:11
  • That’s actually a decent idea to thwart web-crawlers/robots and other malicious stuff creeping on the web. +1 – I'm a TI calculator Sep 20 '19 at 17:14
  • 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 '19 at 18:26
  • @TCooper No, it's nothing. Your mail client pops up and presto there's the address. You go into "Sent Mail" and presto there's the address. – Lightness Races in Orbit Sep 22 '19 at 13:37
  • @LightnessRacesinOrbit it's actually a simple layer of obfuscation that will prevent numerous simple web scrapers that just parse strings looking for a specific format from scraping the email. I would never call it secure but because it's so simple there's practically 0 cost. To me the question is why not? – TCooper Sep 23 '19 at 16:52
  • 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 in Orbit Sep 23 '19 at 17:45
  • @LightnessRacesinOrbit I said I might start implementing it, not that it solves OP's problem. And yes any decent scraper will get around it. I still ask - "why not?" There's no harm and potential benefit. – TCooper Sep 23 '19 at 17:56
  • 1
    There is no potential benefit and the harm is it's harder to implement and maintain. – Lightness Races in Orbit Sep 23 '19 at 23:53
  • sorry I was gone so long, @LightnessRacesinOrbit but you're positive there isn't a single amateur out there running 10 year old scripts that this would obfuscate an email address and prevent them from collecting it? That's an amazing change from what I've read in the last 10 years... and I guess if adding an extra function call here and there is too hard to implement... I can't argue with that - seems trivial to me though. – TCooper Oct 18 '19 at 23:20
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.

rexkogitans
  • 201
  • 1
  • 6
  • 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 '19 at 09:55
  • @P.Goetterup What you describe is no longer a stupid parser, because it has to perform the Google lookup. – rexkogitans Sep 20 '19 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 '19 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 '19 at 12:53
  • @VLAZ that is the other face of the 'automated testing' medal ;P – beppe9000 Sep 20 '19 at 22:33
  • It's actually more difficult than one might think to crawl javascript. JavaScript is Turing Complete, so it is not possible to prove whether a given script will halt or not. This particular script is reasonably easy to predict, so it could be executed rather easily, but that isn't true in the general case. As @ErikA points out, there are standard obfuscators which have been written by very clever programmers to be as obnoxious as possible – Cort Ammon Sep 20 '19 at 23:39
  • I was going to propose something like this. Different levels of obfuscation can be attained. One can use a crypto API or a custom-made obfuscation function - of course the decryption password will have to be served along with the page, but if the decryption/deobfuscation takes place not at page load, but as a result of some user action, this should give some sort of protection against those who don't know any better. – Marc.2377 Sep 22 '19 at 03:45
6

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.

Lort Fasd
  • 61
  • 1
  • 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 '19 at 18:35
  • Along with this I often use [International email](https://en.wikipedia.org/wiki/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 '19 at 19:29
4

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.

Justin
  • 702
  • 5
  • 9
3

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

exussum
  • 156
  • 3
  • That is wild. I have no idea how he did that. – The Anathema Sep 20 '19 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](https://www.google.com/) is doing! – Marc.2377 Sep 22 '19 at 04: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.

AndrolGenhald
  • 15,436
  • 5
  • 45
  • 50
aslum
  • 121
  • 4
1

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>
cg909
  • 111
  • 2
  • 1
    I was happy to learn of XSLT and more from your answer, upvoted. Thank you, –  Sep 22 '19 at 20:17
1

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.

Lie Ryan
  • 31,089
  • 6
  • 68
  • 93