search
Japanese Chinese Nederlands Espanol Italiano Deutsch Francais Twitter Rss Feeds
MicrosoftArticlesForumsFAQs
C# .NET
VB.NET
Visual Studio .NET
ADO.NET
Xml / Xslt
VB 6.0
.NET CF
GDI+
LINQ
Deployment
Security
FoxPro
Silverlight / WPF
Entity Framework
RIA Services

Web ProgrammingArticlesForumsFAQs
JavaScript
ASP
ASP.NET
Web Services

Non-MicrosoftArticlesForumsFAQs
NHibernate
Perl
PHP
Ruby
Java
Linux / Unix
Apple
Open Source

DatabasesArticlesForumsFAQs
SQL Server
Access
Oracle
MySQL
Other Databases

OfficeArticlesForumsFAQs
Excel
Word
Powerpoint
Outlook
Publisher
Money

Operating SystemsArticlesForumsFAQs
Windows 7
Windows Server
Windows Vista
Windows XP
Windows Update
MAC
Linux / UNIX

Server PlatformsArticlesForumsFAQs
BizTalk
Site Server
Exhange Server
IIS

Graphic DesignArticlesForumsFAQs
Macromedia Flash
Adobe PhotoShop
Expression Blend
Expression Design
Expression Web

OtherArticlesForumsFAQs
Subversion / CVS
Ask Dr. Dotnetsky
Active Directory
Networking
Uninstall Virus
Job Openings
Product Reviews
Search Engines
Resumes

 

Spambot Killer ASP.NET Mailto: Hyperlink Control


By Peter Bromberg
Printer Friendly Version
View My Articles
36 Views
    

Shows how to derive from ASP:Hyperlink to provide a control that will automatically obfuscate mailto: hyperlinks to render the contents useless to spam email harvesters.


Everybody knows that the minute you put your email address into the href attribute of an <A> tag with a mailto: prefix, the spam harvesters are going to scrape it and it will increase the amount of absolutely ludicrous spam that (hopefully at least) ends up in your Junk Mail folder.

There are a number of ways to make a "mailto:" link continue to work but to provide obfuscated glop to the spambot harvesting crawlers that is completely useless to them, since they examine the html of the page, not what you "see" in the rendered page.

One way to do this is to convert everything into it's HTML Entity representation. Browsers are happy with this, but since spambots cannot see anything in the HTML they have scraped from the page that Regex-es into what could be an email address, they typically miss it.

There are a number of javascript examples that will do this, but up until today I have not seen any ASP.NET controls that perform this useful action of "entity-izing" the email link.

So, I decided to have a little fun and write a control, and put it out into the public domain for .NET developers. Now when authoring a custom control to perform some functionality, the first thing we should ask ourselves as developers is whether there is already a control that we can derive our class from in order to save time with existing needed functionality that's already present.

And of course in this case, the answer is yes - we have the ASP.NET Hyperlink control; all we really need to do is provide a feature where if the NavigateUrl contains "mailto:" we take over from there.

So this control derives from Hyperlink, and all I needed to do to put it together was to override the control's Render method, and provide my own private method to obfuscate the content that follows so that it works as a mailto: link in the page but is useless to spambot harvesters and the horses-ass punk script kiddies that run them. I don't know about you, but when the last scumbag email spammer is in jail, I will sleep well at night.

Here's the code:

using System;
using System.ComponentModel;
using System.Web.UI;
using System.Web.UI.WebControls;
[assembly : TagPrefix("PAB.WebControls", "pab")]

namespace PAB.WebControls
{
    [DefaultProperty("Text")]
    [ToolboxData("<{0}:EmailLink runat=server></{0}:EmailLink>")]
    public class EmailLink : HyperLink
    {
        private string HtmlObfuscate(string text)
        {
            string tempHtmlObfuscate = null;
            int i = 0;
            int acode = 0;
            string repl = "";
            tempHtmlObfuscate = text;
            for (i = tempHtmlObfuscate.Length; i >= 1; i--)
            {
                acode = Convert.ToInt32(tempHtmlObfuscate[i - 1]);
                if (acode == 32)
                {
                    repl = " ";
                }
                else if (acode == 34)
                {
                    repl = "\"";
                }
                else if (acode == 38)
                {
                    repl = "&";
                }
                else if (acode == 60)
                {
                    repl = "<";
                }
                else if (acode == 62)
                {
                    repl = ">";
                }
                else if (acode >= 32 && acode <= 127)
                {
                    repl = "&#" + Convert.ToString(acode) + ";";
                }
                else
                {
                    repl = "&#" + Convert.ToString(acode) + ";";
                }
                if (repl.Length > 0)
                {
                    tempHtmlObfuscate = tempHtmlObfuscate.Substring(0, i - 1) +
                                        repl + tempHtmlObfuscate.Substring(i);
                    repl = "";
                }
            }
            return tempHtmlObfuscate;
        }


        protected override void Render(HtmlTextWriter writer)
        {
            HyperLink link = this;
            writer.Write("<a");
            if (!string.IsNullOrEmpty(link.NavigateUrl))
            {
                if (link.NavigateUrl.StartsWith("~"))
                    writer.WriteAttribute("href", link.ResolveClientUrl(link.NavigateUrl));
                else if (link.NavigateUrl.StartsWith("mailto:"))
                {
                    link.NavigateUrl = HtmlObfuscate(link.NavigateUrl);
                    writer.WriteAttribute("href", link.NavigateUrl);
                }
                else
                {
                    writer.WriteAttribute("href", link.NavigateUrl);
                }
            }

            if (!string.IsNullOrEmpty(link.CssClass))
                writer.WriteAttribute("class", link.CssClass);

            if (!string.IsNullOrEmpty(link.Target))
                writer.WriteAttribute("target", link.Target);

            foreach (string key in link.Attributes.Keys)
                writer.WriteAttribute(key, link.Attributes[key]);

            writer.Write(">");

            RenderContents(writer);
            writer.Write("</a>");
        }

        protected override void RenderContents(HtmlTextWriter output)
        {
            output.Write(Text);
        }
    }
}
The nice thing about this is that you can still use it as a regular Hyperlink control, the cool stuff only happens if the NavigateUrl property begins with "mailto:". You can also do stuff like this:

NavigateUrl = "mailto:you@yourDomain.com?subject=hi, wanted to get back to you&cc=otherguy@yourdomain.com"

-- and it will take care of the whole thing so when you click on the link, it comes up in your default email client with the TO, the Subject and the CC all prefilled in.

You can download the Visual Studio 2005 Control solution, which includes a Web Application Project "tester" app.  Remember, the less food we give the email spambot crawlers to chew on, the better off we'll all be. Keep all your email links obfuscated.

Biography - Peter Bromberg
Peter Bromberg is a C# MVP, MCP, and .NET expert who has worked in banking, financial and telephony for over 20 years. Pete focuses exclusively on the .NET Platform, and currently develops SOA and other .NET applications for a Fortune 500 clientele. Peter enjoys producing digital photo collage with Maya,playing jazz flute, the beach, and fine wines. You can view Peter's UnBlog and IttyUrl sites.
Please post questions at forums, not via email!

button
Article Discussion: Spambot Killer ASP.NET Mailto: Hyperlink Control
Peter Bromberg posted at Thursday, June 07, 2007 12:20 PM
Original Article
 

Great control, one minor problem...
Mike Levin replied to Peter Bromberg at Saturday, June 23, 2007 4:58 PM

This is super handy, but I'm running into a snag that is probably a silly mistake on my part.  When the user clicks on the link, it opens another browser window with the URL as well as the email client.  The email part is working perfectly...but how do I stop it from opening a new browser window as well?

My code...I'm sure I'm missing something silly...thanks...

<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">

Your registration confirmation failed. Go back to your email and attempt the link again, or click

<pab:emailLink ID="HyperLink1" runat="server" navigateurl="mailto:admin@myurl.com?subject=Need help registering">here </pab:emaillink>to email an administrator for further assistance. Make sure to include your user name in your email.

</asp:Content>

 

 

 

Well, your email client is a separate application -
Peter Bromberg replied to Mike Levin at Saturday, June 23, 2007 7:36 PM

so it will always open in it's own desktop window outside of the browser.

However, have you tried the target="_self" attribute on the emailLink control definition?

 

 

More info....
Mike Levin replied to Peter Bromberg at Sunday, June 24, 2007 8:52 AM

Thanks for the quick response...!

Ok, with a little more testing, here's some more info and a little more detail...

It opens a second browser window with the proper mailto URL.  That window then provides an error that it cannot find the page.  But simultaneously, it brings up the email client as expected in it's own window.  It just leaves this single browser window open with the standard error on it that it can't find the URL (same standard error you would get if you just type garbage into the URL box in the browser).

Here's the weird part.  If I disable Protected Mode (in IE7 under Vista) and then re-enable it, it works just fine!  Seems the "extra window" is occurring when Vista brings up the user control dialog that asks permission to open the email client.  That seems to be the problem somehow.  Very strange.

I've tried different targets.  The only difference is that instead of creating a new window with the errant URL message, it changes the original window to have the mailto URL and the errant URL message, but still opens the email client.  Actually, that seems to make sense I guess.  I'm just curious why the errant message.

One other detail...if I paste the exact same URL into a fresh browser window, it works great...no errant URL message, it just fires up the email client as expected.

I think it must have to do with how the user account control on Vista is interacting with IE7 and the email client...