http://www.perlmonks.org?node_id=89810

As most of us know, the best SPAM prevention measure is to not publish email addresses on public web pages. While this works, there are times when you want (or a client wants you) to publish one or more email addresses.

This article discusses one way you can do so without increasing your SPAM burden. The following script provides a very simple implementation of that technique.

Update: Added Ovid's suggestion and clarified the Two-Face function. Also...put into practice.

#!/usr/bin/perl -wT # --------------------------------------------------------- # Converts email addresses to a format suitable for mailto: # links, one that is reportedly more difficult for spammers # to harvest. # # Note: mailto: tags have other problems. Feedback scripts # may be more effective defenses; however, this can be used # by your HTML "designers" while you're working on a better # solution (Hint: combine CGI.pm with MIME::Lite). # # Revision log and contact info provided in __DATA__ Share # and Enjoy...so long as I get credit, too. # --------------------------------------------------------- use strict; use CGI qw( :standard ); $CGI::HEADERS_ONCE = 1; $CGI::POST_MAX = 1_024; $CGI::DISABLE_UPLOADS = 1; #use CGI::Carp qw( fatalsToBrowser ); #use CGI::Pretty; use HTML::Entities; my $field = "emailaddr"; my $error = cgi_error; if ( $error ) { printForm( "There was a problem with your " . "request.\n\nDetails: $error." ); } elsif ( param( $field ) ) { encodeEmail( param( $field ) ); } else { printForm( "This encodes a simple email address " . '(user@example.com) to a MAILTO: tag ' . "that is more difficult for spammers " . "to harvest.\n\n" . "Please submit the email address you " . "want to encode:\n" ); } exit 1; sub coinFlip # ----------------------------------------------------- # Note that this is weighted heavily in favor of the # codes. # ----------------------------------------------------- { return ( rand() < 0.75 ) ? 1 : 0; } sub encodeEmail # ----------------------------------------------------- # Encodes an email address by randomly converting most # of its characters to ASCII codes. Note weighting in # coinFlip(); according to rumor, this works best when # most, but not all characters are encoded. # ----------------------------------------------------- { my $input = shift; my @chars = split //, $input; my @codes = map { encode_entities( $_, '\x00-\xff' ) } @chars; # See Camel book discussion of srand srand( time() ^ ( $$ + ( $$ << 15 ) ) ); my $result = $input; while ( $result eq $input ) # just in case. { $result = ""; foreach my $index ( 0..$#chars ) { $result .= coinFlip() ? $codes[ $index ] : $chars[ $index ] ; } } printForm( "Your encoded email address " . "is shown below:", $input, $result ); } sub printForm # ----------------------------------------------------- # Prints the HTML. The first parameter is explanatory # text displayed to the user. The second and third # parameters are optional and (respectively) contain # the email address entered by the user and its encoded # version. # ----------------------------------------------------- { my $text = shift; my $email = shift; my $mailto = shift; my $title = "Simple Email Address Encoder"; my $type = "application/x-www-form-urlencoded"; my $source = a( { href=>"http://webdeveloper.com/" . "drweb/19990329-drweb.html" }, "article" ); print header(), start_html( -title => $title ), h1( $title ), p( $text ), start_form( "post", url(), $type ); if ( $mailto ) { my $link = '<a href="mailto:' . "$mailto" . '">' . "$mailto</a>"; print p( "Your link appears like this: $link" ), p( "The value for the mailto link tag is:", br, textarea( -name => "encoded", -default => $mailto, -rows => 3, -columns => 58, -wrap => "virtual" ) ); } print hr, p( 'Enter an e-mail address to encode:', br, textfield( $field, $email, 60, 50 ) ), p( submit(), reset() ), end_form, p( "For more information, please see this ", $source, "." ), end_html; } __DATA__ Contact Info on my home node: http://perlmonks.com/index.pl?node_id=33117 To do list: -- Detect the slight risk of returning all codes and re-run should that happen. I've been told a mixed string is the most effective. -- Fix problems with multiple submissions. There are two, though I think they're from the same bug. -- Podify -- Look for further (reasonable) streamlining. Updates: v0.0.0, 19 Jun 01 - First posted to perlmonks.com v0.0.1, 19 Jun 01: -- Added in HTML::Entities, per [Ovid]. (Yay!) -- Revised coinFlip() and calling code to clarify intent (codes returned 75% of the time).

As always, feedback, meme-prevention, and idiom checks would be appreciated.

--f