# How to redefine @ and . to obfuscate email addresses?

I am writing a small package containing macros I intend to use regularly. Among those macros, I have \mailto with the following definition:

\@ifpackageloaded{hyperref}{%
\def\mailto#1{%
}%
}{%
\def\maitlo#1{%
\url{#1}%
}%
}


What I want to do is redefine @ and . to active characters, so that xxx@yyy.zzz is turned into xxx<at>yyy<dot>zzz. I've tried the following:

\def\mailto#1{%
\begingroup
\catcode@=13
\catcode.=13
\def@{$\langle$at$\rangle$}
\def.{$\langle$dot$\rangle$}
\url{#1}
\endgroup
}


But I get a:

! Undefined control sequence.
\mailto ...e @=\active \catcode .=\active \def@
{$\langle$at$\rangle$} \...
l.XXX \mailto{xxx@yyy.zzz}


Why?

-
An off-topic but related question: does this alteration actually prevent spam? You give away your email address in hundreds of ways all the time, and it's passed to marketers of questionable morality without the possibility of your doing anything about it. I have 500 messages in my spam folder and my email address isn't written in any form on my website. – Ryan Reich Jan 28 '12 at 20:01
I really don't know. That question arose because I learn by doing. Unfortunately, TeX's documentation isn't very programmer-orientated. I wish there were an MSDN-like documentation system somewhere on the web. – Minustar Jan 28 '12 at 20:15
On a related note about email obfuscation and security, see What can cause generated PDF document whose text are not correctly copyable? – Werner Jan 28 '12 at 22:04

There are a few issues with your code. Category codes are fixed when TeX reads an argument, and so reading anything with altered codes is tricky. That applies both to the use of \def. inside \def\mailto and the way you have grabbed the argument of \mailto before you alter category codes. That might lead you to something like

\begingroup
\catcode\@=\active
\catcode\.=\active
\gdef\mailto{%
\begingroup
\catcode\@=\active
\catcode\.=\active
\gdef@{$\langle$at$\rangle$}%
\gdef.{$\langle$dot$\rangle$}%
\mailtoaux
}
\gdef\mailtoaux#1{%
\endgroup
#1%
}
\endgroup


Notice that I've split the group used for \mailto, so that it starts before I grab the argument, and ends after I've grabbed it.

However, this won't work for a URL as the url package does a verbatim read here. In any case, I would avoid active characters (not really needed), and instead to a search-and-replace. I would do this with something like

\newcommand*{\mynil}{\mynil}
\newcommand*{\mailto}[1]{%
\mailtoauxi#1@\mynil@\stop
}
\def\mailtoauxi#1@#2@#3\stop{%
\ifx\mynil#2%
\ERROR
\else
\mailtoauxii#1<at>#2.\mynil.\stop
\fi
}
\makeatletter
\def\mailtoauxii#1.#2.#3\stop{%
\ifx\mynil#2%
\expandafter\@firstoftwo
\else
\expandafter\@secondoftwo
\fi
{\url{#1}}%
{\mailtoauxii#1<dot>#2.#3\stop}%
}
\makeatother


As I said, \url deliberately works to print verbatim, so to get the math mode substitution you want will be a little more work!

-
I could box and split the URL into x components depending on the address. – Minustar Jan 28 '12 at 20:13