LaTeX mailmerge package

The LaTeX mailmerge package is super useful, especially for creating multiple versions of tests.

Before I discovered mailmerge, my workflow for writing a test was basically:

  • Write one version of the test.
  • Make a duplicate of the file.
  • Edit the file to change all the constants.

At least, that was my intended workflow. But typically I would also:

  • Realize that there was some change I wanted to make to the test.
  • Painstakingly make the same change to both versions of the test, double-checking that the wording remained consistent between versions.

Sometimes I would repeat the last two steps multiple times. This was obnoxiously inefficient.

Then I discovered the mailmerge package.

Here is a basic (silly) example illustrating how the package works:

\documentclass[letterpaper, 12pt]{amsart}

%% packages
\usepackage{mailmerge}
\usepackage{fouriernc}
\usepackage{url}
\usepackage{tikz}

\title{Some U.S.~state capital facts}

\begin{document}

  \maketitle

  \mailrepeat{
    The capital of \field{state} is \field{capital}.
    The U.S. Census Bureau estimates that in mid-2017,
    there were \field{population} people living in
    \field{capital}\footnote{\field{cite}}.

  }

  \mailfields{state,capital,population,cite}

  \mailentry{Illinois,Springfield,%
    {167,376},\url{https://goo.gl/YGDdE6}}

  %% Draw a square:
  \vskip 1 em
  \begin{tikzpicture}
    \draw (0, 0) -- (1, 0)
      -- (1, 1) -- (0, 1) -- cycle;
  \end{tikzpicture}
  \vskip 1 em

  \mailentry{Minnesota,St.~Paul,%
    {306,621},\url{https://goo.gl/F6rXZ7}}

  \mailentry{Oregon,Salem,%
    {169,798},\url{https://goo.gl/Zc4tDC}}

  \mailentry{Pennsylvania,Harrisburg,%
    {49,192},\url{https://goo.gl/NQypQG}}

\end{document}

This produces:

SOME U.S. STATE CAPITAL FACTS

The capital of Illinois is Springfield. The U.S. Census Bureau estimates that in mid-2017, there were 167,376 people living in Springfield1.

The capital of Minnesota is St. Paul. The U.S. Census Bureau estimates that in mid-2017, there were 306,621 people living in St. Paul2.

The capital of Oregon is Salem. The U.S. Census Bureau estimates that in mid-2017, there were 169,798 people living in Salem3.

The capital of Pennsylvania is Harrisburg. The U.S. Census Bureau estimates that in mid-2017, there were 49,192 people living in Harrisburg4.

This is followed by the appropriate footnotes.

Typeset output from first example.

Notice:

  • The text you want repeated is specified as the argument of the \mailrepeat macro.
  • Within the \mailrepeat, we specify the mail-merged info with \field{[field name]}
  • The names of the mail merge fields are given as a comma-delimited list with the \mailfields macro.
  • The actual mail-merge is accomplished with the \mailentry macro. The argument to this macro is a comma-delimited list of the material to place into the fields.

I put the silly TikZ square in this example to illustrate that the mail-merged text is placed where the \mailentry occurs in the code.

Spacing is significant in the \mailentry macro. If there is a space next to \field{[field name]} in the \mailrepeat and after the comma the corresponding field in the \mailentry, this will produce an awkward amount of space in the output. For example,

\mailentry{Minnesota, St.~Paul,
{306,621},\url{https://goo.gl/F6rXZ7}}

will produce:

Notice the extra space before the two instances of “St. Paul” and before the population. Compare to what is produced when there is no space before the comma and there is a % before the line break (which prevents the line break from being treated as a space):

\mailentry{Minnesota,St.~Paul,%
{306,621},\url{https://goo.gl/F6rXZ7}}


It’s very subtle, but I am a perfectionist.

If you have many fields, the comma-delimited list argument to the \mailentry can get unwieldy. One trick I use is to end each entry with a comment containing the field name:

  \mailentry{Minnesota%state
    ,St.~Paul%capital
    ,{306,621}%population
    ,\url{https://goo.gl/F6rXZ7}%cite
    }

Especially when the fields are difficult to tell apart based on content (e.g., when they are different constants for math problems), this makes it easier to know which field you are changing. Also, the comments prevent any space or line break before the comma from affecting the output.

For a test, each version would correspond to a single \mailentry. Consider this made-up quiz, which has two versions (Form A and B):

\documentclass[letterpaper, 11pt]{article}

%% packages
\usepackage{amsmath}
\usepackage{mailmerge}
\usepackage{fouriernc}
\usepackage{enumitem}
\usepackage{fullpage}

\begin{document}

  \mailrepeat{
    \setcounter{page}{1}
    \centerline{\textbf{Quiz \#1}, Form \field{form}}
    \vskip 1 em

    \begin{enumerate}
      \item (2 points) Expand
      \(\left(x^{\field{exponent1}} + 2x\right)^2\).


      \vfill

      \item (3 points) Suppose
      \(f(x) =
        \field{coeff1}x^2 + \field{coeff2}x + 1\).
      Find \(f(5)\).
      \vfill

    \end{enumerate}

    \newpage

    \begin{enumerate}[resume]
      \item (5 points) Solve for \(x\):
      \[\field{coeff3}x^4 - \field{coeff4}x^3
        = 0\]

      \vfill

    \end{enumerate}
    \newpage
  }


  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %%% Mail merge info:

  \mailfields{form, coeff1, coeff2,
    coeff3, coeff4, exponent1}

  \mailentry{A%form
  ,6%coeff1
  ,8%coeff2
  ,2%coeff3
  ,7%coeff4
  ,3%exponent1
  }

  \mailentry{B%form
  ,5%coeff1
  ,9%coeff2
  ,3%coeff3
  ,5%coeff4
  ,5%exponent1
  }
\end{document}

At the start of the \mailrepeated code is the macro \setcounter{page}{1}, which resets the page number to 1; otherwise, Form B would start on Page 3. Also, I ended the \mailrepeated code with a \newpage, ensuring that each version is on a separate page.

If you print \(\lceil N/2\rceil\) copies of the resulting PDF (where N is the number of students in your course), two-sided, then the pile of quizzes will be alternated by version as they come out of the printer, ready to hand out to your class.