Customize Mail Merge in Word Documents Using C# and VB.NET

Mail merging in GemBox.Document is very flexible and customizable. It allows you to customize the MailMerge.FieldMerging event to suit your data importing requirements.

The event handler has access to a FieldMergingEventArgs object for each merging field. With it, you can change the value or the format of the data inserted or replace the Run element's insertion with something else like Picture or Hyperlink elements.

See the Merge Pictures example for an easier way to import Picture elements in the mail merge process. Also, you can format the Date and Time or Numeric values by simply using formatting switches on the MERGEFIELD element itself (\@ for dates and \# for numbers).

The following example shows how you can perform a customized mail merge.

Word document generated from customizable mail merge
Screenshot of Word file created with customized merge
Upload your file (Drag file here)
using GemBox.Document;

class Program
{
    static void Main()
    {
        // If using the Professional version, put your serial key below.
        ComponentInfo.SetLicense("FREE-LIMITED-KEY");

        var document = DocumentModel.Load("%InputFileName%");

        document.MailMerge.FieldMerging += (sender, e) =>
        {
            if (e.IsValueFound && e.Value != null)
            {
                switch (e.FieldName)
                {
                    case "CheckedField":
                        bool checkedValue = (bool)e.Value;
                        var run = (Run)e.Inline;
                        run.CharacterFormat.FontColor = checkedValue ? Color.Green : Color.Red;
                        run.Text = checkedValue ? "☑" : "☒";
                        break;

                    case "LinkField":
                        var linkValue = ((string Address, string DisplayText))e.Value;
                        e.Inline = new Hyperlink(e.Document, linkValue.Address, linkValue.DisplayText);
                        break;

                    case "ImageField":
                        var imagePath = e.Value.ToString();
                        e.Inline = new Picture(e.Document, imagePath);
                        break;
                }
            }
        };

        document.MailMerge.Execute(
            new
            {
                CheckedField = true,
                LinkField = (Address: "https://www.gemboxsoftware.com/", DisplayText: "GemBox Homepage"),
                ImageField = "%#Dices.png%"
            });

        document.Save("Merged Customizations Output.%OutputFileType%");
    }
}
Imports GemBox.Document

Module Program

    Sub Main()

        ' If using the Professional version, put your serial key below.
        ComponentInfo.SetLicense("FREE-LIMITED-KEY")

        Dim document = DocumentModel.Load("%InputFileName%")

        AddHandler document.MailMerge.FieldMerging,
            Sub(sender, e)
                If e.IsValueFound And e.Value IsNot Nothing Then
                    Select Case e.FieldName

                        Case "CheckedField"
                            Dim checkedValue As Boolean = DirectCast(e.Value, Boolean)
                            Dim run = DirectCast(e.Inline, Run)
                            run.CharacterFormat.FontColor = If(checkedValue, Color.Green, Color.Red)
                            run.Text = If(checkedValue, "☑", "☒")
                            Exit Select

                        Case "LinkField"
                            Dim linkValue = DirectCast(e.Value, (Address As String, DisplayText As String))
                            e.Inline = New Hyperlink(e.Document, linkValue.Address, linkValue.DisplayText)
                            Exit Select

                        Case "ImageField"
                            Dim imagePath = e.Value.ToString()
                            e.Inline = New Picture(e.Document, imagePath)
                            Exit Select

                    End Select
                End If
            End Sub

        document.MailMerge.Execute(
            New With
            {
                .CheckedField = True,
                .LinkField = (Address:="https://www.gemboxsoftware.com/", DisplayText:="GemBox Homepage"),
                .ImageField = "%#Dices.png%"
            })

        document.Save("Merged Customizations Output.%OutputFileType%")

    End Sub
End Module

Insert HTML, RTF, and DOCX with mail merge

GemBox.Document also provides a MailMerge.FieldMappings dictionary that allows you to define custom mappings of field names to data source names.

By combining the custom mapping and merging of the mail merge process, you can define your type of MERGEFIELD elements. For instance, you can use an arbitrary prefix in the names of your MERGEFIELD elements and then handle merging those fields as needed.

The following example shows how to define and use MERGEFIELD elements that insert HTML, RTF, or DOCX content in the mail merge process.

  • MERGEFIELD with the "Html:" prefix will insert an HTML formatted text from the provided source.
  • MERGEFIELD with the "Rtf:" prefix will insert an RTF formatted text from the provided source.
  • MERGEFIELD with the "Docx:" prefix will insert a DOCX file's section from the provided source.
Word document generated from importing HTML, RTF and DOCX with mail merge
Screenshot of inserted HTML, RTF and DOCX content in the mail merge process
Upload your file (Drag file here)
using GemBox.Document;

class Program
{
    static void Main()
    {
        // If using the Professional version, put your serial key below.
        ComponentInfo.SetLicense("FREE-LIMITED-KEY");

        var document = DocumentModel.Load("%InputFileName%");

        // Map merge fields with prefix to data source without prefix.
        // E.g. "Html:MyName" field's name to "MyName" data source name.
        foreach (string fieldName in document.MailMerge.GetMergeFieldNames())
        {
            int index = fieldName.IndexOf(':');
            if (index > 0 && !document.MailMerge.FieldMappings.ContainsKey(fieldName))
                document.MailMerge.FieldMappings.Add(fieldName, fieldName.Substring(index + 1));
        }

        // Customize mail merge to support our custom prefixes.
        document.MailMerge.FieldMerging += (sender, e) =>
        {
            if (!e.IsValueFound)
                return;

            bool customImport = true;

            if (e.FieldName.StartsWith("Html:"))
                e.Field.Content.End.LoadText((string)e.Value, new HtmlLoadOptions() { InheritCharacterFormat = true });
            else if (e.FieldName.StartsWith("Rtf:"))
                e.Field.Content.End.LoadText((string)e.Value, new RtfLoadOptions());
            else if (e.FieldName.StartsWith("Docx:"))
                e.Field.Content.End.InsertRange(DocumentModel.Load((string)e.Value).Sections[0].Blocks.Content);
            else
                customImport = false;

            if (customImport)
            {
                // Remove the default import.
                e.Inline = null;

                // Check if the content is inserted into the same parent paragraph or added after it.
                // This depends on whether the data source contains inline-level or block-level elements.
                // If it's added after, then remove the empty parent which used to contain merge field.
                if (e.Field.ParentCollection.Count == 1)
                    e.Field.Parent.Content.Delete();
            }
        };

        document.MailMerge.Execute(
            new
            {
                Field1 = @"{\rtf1\ansi\deff0{\fonttbl{\f0 Arial Black;}}{\colortbl ;\red255\green128\blue64;}\f0\cf1 This is rich formatted text (in RTF format).}",
                Field2 = "<p style='font-family:Arial Narrow;color:royalblue;'>This is another rich formatted text (in HTML format).</p>",
                Field3 = "<p style='font-family:Arial Narrow;color:seagreen;'>And another rich formatted text (in HTML format).</p>",
                Field4 = "%#Reading.docx%"
            });

        document.Save("Merged Custom Types Output.%OutputFileType%");
    }
}
Imports GemBox.Document

Module Program

    Sub Main()

        ' If using the Professional version, put your serial key below.
        ComponentInfo.SetLicense("FREE-LIMITED-KEY")

        Dim document = DocumentModel.Load("%InputFileName%")

        ' Map merge fields with prefix to data source without prefix.
        ' E.g. "Html:MyName" field's name to "MyName" data source name.
        For Each fieldName As String In document.MailMerge.GetMergeFieldNames()
            Dim index As Integer = fieldName.IndexOf(":"c)
            If index > 0 AndAlso Not document.MailMerge.FieldMappings.ContainsKey(fieldName) Then
                document.MailMerge.FieldMappings.Add(fieldName, fieldName.Substring(index + 1))
            End If
        Next

        ' Customize mail merge to support our custom prefixes.
        AddHandler document.MailMerge.FieldMerging,
            Sub(sender, e)
                If Not e.IsValueFound Then Return

                Dim customImport As Boolean = True

                If e.FieldName.StartsWith("Html:") Then
                    e.Field.Content.End.LoadText(CStr(e.Value), New HtmlLoadOptions() With {.InheritCharacterFormat = True})
                ElseIf e.FieldName.StartsWith("Rtf:") Then
                    e.Field.Content.End.LoadText(CStr(e.Value), New RtfLoadOptions())
                ElseIf e.FieldName.StartsWith("Docx:") Then
                    e.Field.Content.End.InsertRange(DocumentModel.Load(CStr(e.Value)).Sections(0).Blocks.Content)
                Else
                    customImport = False
                End If

                If customImport Then
                    ' Remove the default import.
                    e.Inline = Nothing

                    ' Check if the content is inserted into the same parent paragraph or added after it.
                    ' This depends on whether the data source contains inline-level or block-level elements.
                    ' If it's added after, then remove the empty parent which used to contain merge field.
                    If e.Field.ParentCollection.Count = 1 Then e.Field.Parent.Content.Delete()
                End If
            End Sub

        document.MailMerge.Execute(
            New With
            {
                .Field1 = "{\rtf1\ansi\deff0{\fonttbl{\f0 Arial Black;}}{\colortbl ;\red255\green128\blue64;}\f0\cf1 This is rich formatted text (in RTF format).}",
                .Field2 = "<p style='font-family:Arial Narrow;color:royalblue;'>This is another rich formatted text (in HTML format).</p>",
                .Field3 = "<p style='font-family:Arial Narrow;color:seagreen;'>And another rich formatted text (in HTML format).</p>",
                .Field4 = "%#Reading.docx%"
            })

        document.Save("Merged Custom Types Output.%OutputFileType%")

    End Sub
End Module

See also


Next steps

GemBox.Document is a .NET component that enables you to read, write, edit, convert, and print document files from your .NET applications using one simple API. How about testing it today?

Download Buy