chrisphan.com

LaTeX mailmerge package

An analog clock reading 9:402018-05-27 / 2018-W21-7T21:40:57-05:00 / 0x5b0b6c39

Categories: LaTeX

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:

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

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:

LaTeX
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
\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.

A square

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:

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,

LaTeX

36
37

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

will produce:

Part of the output. "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. Paul". There is an awkward extra bit of space before the population and before each "St. Paul"

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):

LaTeX

36
37

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

Part of the output. The same text as in the last graphic but no weird spaces

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:

LaTeX
% [...]
\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):

LaTeX
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
\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.