New to Telerik Document ProcessingStart a free 30-day trial

Mail Merge

Updated on Jun 16, 2026

Mail merge is a feature that produces personalized documents from a template holding fixed content and variables. The variables are called Merge Fields and are replaced through the merge process with content from a specified data source.

Inserting Merge Fields

Merge fields are a type of Fields and can be added in a template document through the InsertField() method of RadFlowDocumentEditor. The method requires the code representation of the field and the result which is shown in the template before the document is mail-merged.

The code snippet in Example 1 shows how to initialize a RadFlowDocumentEditor instance and insert a merge field.

Example 1: Insert a Merge Field

C#
RadFlowDocument document = new RadFlowDocument();
RadFlowDocumentEditor editor = new RadFlowDocumentEditor(document);
editor.InsertField("MERGEFIELD FirstName", "");

Additionally, you can add a field to a Paragraph manually by creating a FieldInfo instance and placing its start, code, separator, result, and end in the block. Example 2 shows the manual approach for adding a merge field.

Example 2: Add a Merge Field Manually

C#
Paragraph paragraph = new Paragraph(document);
document.Sections.First().Blocks.Add(paragraph);

FieldInfo field = new FieldInfo(document);

paragraph.Inlines.Add(field.Start);
paragraph.Inlines.AddRun("MERGEFIELD LastName");
paragraph.Inlines.Add(field.Separator);
paragraph.Inlines.AddRun("");
paragraph.Inlines.Add(field.End);

Performing Mail Merge

You can perform mail merge over a template document containing merge fields. For this action, use the MailMerge() method of RadFlowDocument. The method accepts a collection of elements as a parameter.

During the operation, each MergeField is replaced with the corresponding information from the data source record in a new RadFlowDocument instance. Every subsequent entry in the data source is appended to a single resulting document which is returned by the method. The original template stays unmodified.

Example 3 shows a sample data source.

Example 3: Sample Data Source

C#
List<MailMergeRecord> mailMergeDataSource = new List<MailMergeRecord>()
    {
        new MailMergeRecord()
        {
FirstName = "Andrew",
LastName = "Fuller"
        },
        new MailMergeRecord()
        {
        FirstName = "Nancy",
LastName = "Davolio"
        },
    };
        }
        


     public class MailMergeRecord
        {
public string FirstName { get; set; }
public string LastName { get; set; }
        }

Example 4 performs the mail merge operation over a previously defined template document using the data source from Example 3.

Example 4: Perform Mail Merge

C#
RadFlowDocument mailMergeResult = document.MailMerge(mailMergeDataSource);

Nested Mail Merge

The nested mail merge feature is supported starting with R1 2022. It allows you to merge data sources that contain nested data. For example, your business object can contain a list of other objects and this feature allows you to access the properties of the underlying objects. To use the underlying objects, you need to declare a group. The following group tags are supported:

  • BeginGroup/EndGroup
  • TableStart/TableEnd
  • RangeStart/RangeEnd
  • GroupStart/GroupEnd

All tag pairs work equally and more than one option exists to improve the readability of the documents.

Exception: When a table row has only one cell, using the TableStart/TableEnd tags over the whole content of that cell creates a new row for each value. Every other pair of tags (BeginGroup/EndGroup, RangeStart/RangeEnd, GroupStart/GroupEnd) are interchangeable and put the values on the same row inside that cell.

A single cell (spanning the whole row) with TableStart/TableEnd tags:

Mail merge single cell row with TableStart and TableEnd tags

A single cell (spanning the whole row) with a tag group different than TableStart/TableEnd:

Mail merge single cell row with alternative group tags

The following example demonstrates how to use nested mail merge.

First, define a data source that contains an IEnumerable of objects.

Example 5: Nested Mail Merge Data Source

C#
public List<Team> GetTeams()
{
    var teams = new List<Team>();
    var team1 = new Team();
    team1.TeamName = "Team 1";
    team1.Players.Add(new Player() { FirstName = "John", LastName = "Baker" });
    team1.Players.Add(new Player() { FirstName = "Sam ", LastName = "Wayne" });
    teams.Add(team1);

    var team2 = new Team();
    team2.TeamName = "Team 2";
    team2.Players.Add(new Player() { FirstName = "Patrick", LastName = "Gibbs" });
    team2.Players.Add(new Player() { FirstName = "Oscar", LastName = "Stevens" });
    teams.Add(team2);

    return teams;
}

public class Team
{
    public string TeamName { get; set; }

    public List<Player> Players { get; set; }

    public Team()
    {
        this.Players = new List<Player>();
    }
}
public class Player
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

Then, add the fields using the specific supported names. In this example, the fields are added to the table using the TableStart/TableEnd tags. This is not mandatory and you can use a tag of your choosing.

Example 6: Perform Nested Mail Merge

C#
RadFlowDocument document = new RadFlowDocument();
RadFlowDocumentEditor editor = new RadFlowDocumentEditor(document);

editor.InsertParagraph();
editor.InsertField("MERGEFIELD TeamName", "");
editor.InsertParagraph();
editor.InsertText("Players:");

var playersTable = editor.InsertTable(2, 2);
playersTable.PreferredWidth = new TableWidthUnit(TableWidthUnitType.Percent, 100);
document.StyleRepository.AddBuiltInStyle(BuiltInStyleNames.TableGridStyleId);
playersTable.StyleId = BuiltInStyleNames.TableGridStyleId;

playersTable.Rows[0].Cells[0].Blocks.AddParagraph().Inlines.AddRun("First Name");
playersTable.Rows[0].Cells[1].Blocks.AddParagraph().Inlines.AddRun("Last Name");

var firstNameParagraph = playersTable.Rows[1].Cells[0].Blocks.AddParagraph();
editor.MoveToParagraphStart(firstNameParagraph);
editor.InsertField("MERGEFIELD TableStart:Players", "");
editor.InsertField("MERGEFIELD FirstName", "");

var lastNameParagraph = playersTable.Rows[1].Cells[1].Blocks.AddParagraph();
editor.MoveToParagraphStart(lastNameParagraph);
editor.InsertField("MERGEFIELD LastName", "");
editor.InsertField("MERGEFIELD TableEnd:Players", "");

RadFlowDocument mailMergeResult = document.MailMerge(GetTeams());

One Row vs Multiline Mail Merge

With the nested mail merge feature, you can add all items to a single line. Add the group and regular fields to a single paragraph.

Figure 1: Mail merge on a single row and the results

Mail merge on a single row and the results

To separate the items into several rows, close the group on the next row.

Figure 2: Mail merge on multiple rows and the results

Mail merge on multiple rows and the results

See Also