# How to extend a macro for e-mail addresses to support multiple arguments?

I prepared the following macros to format e-mail adresses in a e-mail header.

\usepackage{xifthen}% Provides \ifthenelse and \isempty

% E-Mail header strings with format.
\newcommand{\fromString}{\textbf{From:} }
\newcommand{\toString}{\textbf{To:} }

% E-Mail with or without alias.
\newcommand{\email}[2][]{%
\ifthenelse{\isempty{#1}}%
{<#2>}% E-Mail only
{"#1" <#2>}% Alias and E-Mail
}

\newcommand{\emailFrom}[2][]{%
\ifthenelse{\isempty{#1}}%
{\fromString \email{#2}\\}% E-Mail only
{\fromString \email[#1]{#2}\\}% Alias and E-Mail
}

\newcommand{\emailTo}[2][]{%
\ifthenelse{\isempty{#1}}%
{\toString \email{#2}\\}% E-Mail only
{\toString \email[#1]{#2}\\}% Alias and E-Mail
}


The macros can be used as illustrated by the following examples. Please mind that [] are used for optional arguments instead of {}.

\email[Doe, John]{john.doe@stackexchange.com}
\emailFrom[Doe, John]{john.doe@stackexchange.com}
\emailFrom{john.doe@stackexchange.com}
\emailTo[Doe, John]{john.doe@stackexchange.com}
\emailTo{john.doe@stackexchange.com}


The formatted output looks like this:

"Doe, John" <john.doe@stackexchange.com>
From: "Doe, John" <john.doe@stackexchange.com>
From: <john.doe@stackexchange.com>
To: "Doe, John" <john.doe@stackexchange.com>
To: <john.doe@stackexchange.com>

How could I extend the macro so that I can use it with multiple e-mail addresses? The following example should explain the issue. As you can see by the third example, the occurance of the alias is individual for each e-mail entry.

To: "Doe, John" <john.doe@stackexchange.com>, "Doe, Jane" <jane.doe@stackexchange.com>
To: <john.doe@stackexchange.com>, <jane.doe@stackexchange.com>
To: <john.doe@stackexchange.com>, "Doe, Jane" <jane.doe@stackexchange.com>

Since I am new to using macros in latex you are also welcome to generally improve my commands or leave comments to do so.

Update:

While working with several email I realized that it can also happen, that there is no email address given, only the email alias. This happens when someone forwards emails e.g., as an internal conversation in a company. Nevertheless, I accept this format as a valid email header. Do you see any chance to include this schema in the macros? Here is an example.

From: John Doe
Date: Wed, 22 Aug 2012 23:42:00 +0200
To: Jane Doe

-

I'd use a different syntax for the cases of one address and multiple addresses:

\documentclass{article}
\usepackage[T1]{fontenc}
\makeatletter
\newif\if@emailenv
\newenvironment{emails}[1][\ignorespaces]
{\set@email@separator{#1}\@emailenvtrue\begin{flushleft}}
{\end{flushleft}}
\def\set@email@separator#1{%
\def\email@separator{#1\def\email@separator{,}}}
\newcommand{\@email}[2][]{%
\if@emailenv\else\begin{flushleft}\fi
\email@separator\space
\if\relax\detokenize{#1}\relax\else"#1" \fi
\texttt{<#2>}%
\if@emailenv\ignorespaces\else\end{flushleft}\fi
}
\newcommand{\email}{%
\if@emailenv\else\set@email@separator{\ignorespaces}\fi\@email}
\newcommand{\emailTo}{%
\if@emailenv\else\set@email@separator{\textbf{To:}}\fi\@email}
\newcommand{\emailFrom}{%
\if@emailenv\else\set@email@separator{\textbf{From:}}\fi\@email}
\newcommand{\emailsFrom}{\emails[\textbf{From:}]}
\newcommand{\emailsTo}{\emails[\textbf{To:}]}
\let\endemailsFrom\endemails
\let\endemailsTo\endemails
\makeatother

\begin{document}
\email{pippo@stackexchange.com}

\email[Doe, John]{john.doe@stackexchange.com}

\emailTo{pippo@stackexchange.com}

\emailTo[Doe, John]{john.doe@stackexchange.com}

\emailFrom{pippo@stackexchange.com}

\emailFrom[Doe, John]{john.doe@stackexchange.com}

\begin{emails}
\email{pippo@stackexchange.com}
\email[Doe, John]{john.doe@stackexchange.com}
\email[Doe, Jane]{jane.doe@stackexchange.com}
\end{emails}

\begin{emailsTo}
\email{pippo@stackexchange.com}
\email[Doe, John]{john.doe@stackexchange.com}
\email[Doe, Jane]{jane.doe@stackexchange.com}
\end{emailsTo}

\begin{emailsFrom}
\email{pippo@stackexchange.com}
\email[Doe, John]{john.doe@stackexchange.com}
\email[Doe, Jane]{jane.doe@stackexchange.com}
\end{emailsFrom}

\end{document}


-
Pretty impressing output. What I do not like is that you already mix in format commands, that I would pass into the functions in order stay flexible. –  JJD Sep 1 '12 at 16:49
Just change \textbf{From:} into \toString and similarly for "To", if you prefer. –  egreg Sep 1 '12 at 17:44
No offense! But there is also the quotation hidden somewhere and there are many repetitions of conditional clauses that I would extract into a function e.g., \if@emailenv\else\set@email@separator{ ... }\fi\@email} I find them to be redundant. –  JJD Sep 1 '12 at 21:17
While I prepared my documentation I reviewed the commands and decided to use macro. The grouping into environments helps to keep some level of readability and has a logical structure. Only, I find your macro a little overwhelming. @Tom Bombadil: No offense. I appreciate your work!!! –  JJD Sep 7 '12 at 9:12
FYI: I opened another question to protect the email header against pagebreaks. –  JJD Sep 7 '12 at 9:39

This solution uses foreach from TikZ / PGF. You specify the names and mails as a list of the form name/mail,name/mail and so on:

## The Code

\documentclass[parskip]{scrartcl}
\usepackage[margin=15mm]{geometry}
\usepackage{tikz}
\usepackage{xifthen}

\newcommand{\toString}{\textbf{To:} }

\newcommand{\emailto}[1]% list ; "/" separates mail and name, "," separates people
{   \xdef\maillist{}% empty maillist
\foreach \x/\y [count=\c] in {#1}% for each iteration over the name/mail list, increase \c by one
{   \ifthenelse{\c=1}% if first iteration...
\ifthenelse{\equal{\x}{}}% if no name given
{\xdef\maillist{\maillist\addcomma$<$\y$>$}}% put just <mail>
{\xdef\maillist{\maillist\addcomma"\x"$<$\y$>$}}% else put "name"<mail>
}
\toString\maillist% output of the final list
}

\begin{document}

\emailto{John Doe/John.Doe@a.bc,Jane Dane/Jane.Dane@way.ne,/Denny.Crane@law.com}

\end{document}


## The Result

Edit 1: A little generalization: Now you can reuse \email for other definitions. I have no idea how to do this with with optional parameters, as their number is not equal to the parameters.

## The Code

\newcommand{\email}[1]% list ; "/" separates mail and name, "," separates people
{   \xdef\maillist{}% empty maillist
\foreach \x/\y [count=\c] in {#1}% for each iteration over the name/mail list, increase \c by one
{   \ifthenelse{\c=1}% if first iteration...
\ifthenelse{\equal{\x}{}}% if no name given
{\xdef\maillist{\maillist\addcomma$<$\y$>$}}% put just <mail>
{\xdef\maillist{\maillist\addcomma"\x"$<$\y$>$}}% else put "name"<mail>
}
}

\newcommand{\emailto}[1]
{   \email{#1}
\textbf{To: }\maillist
}

\newcommand{\emailfrom}[1]
{   \email{#1}
\textbf{From: }\maillist
}


## The Result

\emailto{John Doe/John.Doe@a.bc,Jane Dane/Jane.Dane@way.ne,/Denny.Crane@law.com}

\emailfrom{John Doe/John.Doe@a.bc,Jane Dane/Jane.Dane@way.ne,/Denny.Crane@law.com}


Edit 2: And Now for Something Completely Different:
This solution uses xstring, the list format is (name)email;.
Please note that you also have to terminate the list with a semicolon ;

## The Code

\documentclass[parskip]{scrartcl}
\usepackage[margin=10mm]{geometry}
\usepackage{xifthen}
\usepackage{xstring}
\usepackage{xcolor}

\newcommand{\email}[1]% (<name>)<email>;(<name>)<email>
{   \xdef\mylist{#1} % set mylist to the input
\xdef\myentry{} % empty myentry
\xdef\myname{} % empty myname
\xdef\myemail{} % empty myemail
\xdef\myoutput{} % empty myoutput
\xdef\mynumber{} % empty mynumber
\StrBefore{\mylist}{;}[\myentry]  % get everything in mylist before ; and save it to myentry, so this should be the first person, e.g (name)mail
\StrLen{\myentry}[\mynumber] % save length of myentry to mynumber
\whiledo{\mynumber>0} % while myentry is not empty (e.g. length > 0)
{   \StrBetween{\myentry}{(}{)}[\myname] % extract what is between ( and ) in myentry and save it to myname
\StrPosition{\myentry}{)}[\mynumber] % save position of ) to mynumber
\ifthenelse{\mynumber>0} % if the character ) is found in myentry
{   \StrBehind{\myentry}{)}[\myemail]} % then get everything behind ), e.g the email
{ \xdef\myemail{\myentry}}% otherwise (e.g. no name present) set myemail to myentry
\StrLen{\myname}[\mynumber] % set mynumber to the length of mynem
\ifthenelse{\mynumber>0} % if length of myname is non-zero (e.g one was provided)
{   \xdef\myoutput{\myoutput"\myname"$<$\myemail$>$}} % then print "name"<mail>
{ \xdef\myoutput{\myoutput$<$\myemail$>$}}  % else print <mail>
\StrBehind{\mylist}{;}[\mylist] % delete everything up to the first ; e.g the entry that was just worked with
\StrBefore{\mylist}{;}[\myentry] % new myentry is everything before the next ;
\StrLen{\myentry}[\mynumber] % determine length of myentry and save that number to mynumber
\ifthenelse{\mynumber>0} % if a new myentry is present (e.g not end of list)
{   \xdef\myoutput{\myoutput,}} % then add a comma
{} % else do nothing
}
%\myoutput  % after all entrys were processed, output the result
}

\newcommand{\eMailTo}[1]%
{   \email{#1}
\textbf{To: }\myoutput
}

\newcommand{\eMailFromColor}[2][green!50!gray]%
{   \email{#2}
\textcolor{#1}{\textbf{From: }\myoutput}
}

\begin{document}

\eMailTo{(Doe, John)John.Doe@a.bc;(Dane, J. A. N. E)Jane.Dane@way.ne;Denny.Crane@law.com;}

\eMailFromColor{(Doe, John)John.Doe@a.bc;(Dane, J. A. N. E)Jane.Dane@way.ne;Denny.Crane@law.com;}

\eMailFromColor[red!80!black]{(Doe, John)John.Doe@a.bc;(Dane, J. A. N. E)Jane.Dane@way.ne;Denny.Crane@law.com;}

\end{document}


## The Result

-
Pretty nice! Though, I have two requests. (1) I created the \email macro so that I can re-use it for \emailTo, \emailCc and \emailFrom and avoid duplicate code by this. How would integrate this? (2) I do not like the leading / in the example w/o the alias too much. Is there any alternative with optional parameters? –  JJD Sep 1 '12 at 14:38
There is a problem when the alias is written in order last name, first name e.g., Doe, John. The commata is recognized as a separator between emails, but this a common writing scheme! –  JJD Sep 1 '12 at 15:15
Slightly less ugly, but still not nice: surround the whole name with curly braces, like {Doe, John} –  Tom Bombadil Sep 1 '12 at 17:41