# Creating 100% Compliant ZUGFeRD and Factur-X Invoices using MailMerge in C#

> The ZUGFeRD and Factur-X standards are hybrid electronic invoice formats regulated and required by some European governments. This article shows how to create a valid ZUGFeRD compliant invoice PDF document from scratch.

- **Author:** Bjoern Meyer
- **Published:** 2023-02-09
- **Modified:** 2026-07-17
- **Description:** The ZUGFeRD and Factur-X standards are hybrid electronic invoice formats regulated and required by some European governments. This article shows how to create a valid ZUGFeRD compliant invoice PDF document from scratch.
- **5 min read** (912 words)
- **Tags:**
  - ASP.NET
  - Zugferd
  - Invoice
- **Web URL:** https://www.textcontrol.com/blog/2023/02/09/creating-compliant-zugferd-and-facturx-invoices-using-mailmerge-in-csharp/
- **LLMs URL:** https://www.textcontrol.com/blog/2023/02/09/creating-compliant-zugferd-and-facturx-invoices-using-mailmerge-in-csharp/llms.txt
- **LLMs-Full URL:** https://www.textcontrol.com/blog/2023/02/09/creating-compliant-zugferd-and-facturx-invoices-using-mailmerge-in-csharp/llms-full.txt
- **GitHub Repository:** https://github.com/TextControl/TXTextControl.Core.MailMerge.Zugferd

---

The ZUGFeRD / Factur-X standard is a hybrid electronic invoice format that consists of two parts:

- A PDF visual, human-readable representation of the invoice.
- An XML file that contains invoice data in a structured form that can be processed automatically.

This article shows how to use the MailMerge class to merge invoice data into a template and how to embed the generated ZUGFeRD XML to the final PDF document.

> **ZUGFeRD-csharp**
> 
> In this sample, we utilize the GitHub project *ZUGFeRD-csharp* that is also available as a NuGet package.
> 
> [ZUGFeRD-csharp GitHub repository ](https://github.com/stephanstapel/ZUGFeRD-csharp)
> 
> [ZUGFeRD-csharp NuGet package ](https://www.nuget.org/packages/ZUGFeRD-csharp/)

### The Template

The following screenshot shows a very simple invoice template with fields according to the following **Order** data structure. You can see the merge fields for the **Buyer** and the merge block highlighted in red to repeat the **LineItems**.

![Invoice template](https://s1-www.textcontrol.com/assets/dist/blog/2023/02/09/a/assets/template.webp "Invoice template")

### The Data Source

The class **Order** contains all data required for an invoice generation process including address data for the buyer, the seller and the sold line items. Some properties such as **LineTotalAmount** and **TaxTotalAmount** are calculated automatically based on the added line items.

```
public class Order {
  public int Id { get; set; }
  public DateTime OrderDate { get; set; }
  public ContractParty Buyer { get; set; }
  public ContractParty Seller { get; set; }
  public Decimal Allowance { get; set; }
  public Decimal Vat { get; set; } = 6.5M;
  public List<LineItem> LineItems { get; set; } = new List<LineItem>();
  
  public Decimal LineTotalAmount {
    get {
      return this.LineItems.Sum(item => item.GrossPrice * item.Quantity);
    }
  }

  public Decimal TaxTotalAmount {
    get {
      return (this.LineTotalAmount / 100) * this.Vat;
    }
  }

  public Decimal GrandTotalAmount {
    get {
      return this.LineTotalAmount + this.TaxTotalAmount;
    }
  }

  public class LineItem {
    public string Name { get; set; }
    public string Description { get; set; }
    public QuantityCodes QuantityCode { get; set; } = QuantityCodes.H87;
    public int Quantity { get; set; }
    public decimal GrossPrice { get; set; }
  }

  public class Seller : ContractParty { }
  public class Buyer : ContractParty { }

  public class ContractParty {
    public int Id { get; set; }
    public string Name { get; set; }
    public string PostalCode { get; set; }
    public string City { get; set; }
    public string Address { get; set; }
    public CountryCodes CountryCodes { get; set; }
    public ContractPartyContact BuyerContact { get; set; }
  }

  public class ContractPartyContact {
    public string FirstName { get; set; }
    public string LastName { get; set; }
  }
  
}
```

Additionally, the class **Order** contains a property that generates the required ZUGFeRD XML. The property get method is basically matching the data source to the required properties of the *InvoiceDescriptor* that generates the XML.

```
public byte[] ZugferdXML {
  get {
    var invoice = InvoiceDescriptor.CreateInvoice(this.Id.ToString(),
        this.OrderDate, CurrencyCodes.USD);

    invoice.SetBuyer(this.Buyer.Name,
      this.Buyer.PostalCode,
      this.Buyer.City,
      this.Buyer.Address,
      this.Buyer.CountryCodes,
      this.Buyer.Id.ToString());

    invoice.SetSeller(this.Seller.Name,
      this.Seller.PostalCode,
      this.Seller.City,
      this.Seller.Address,
      this.Seller.CountryCodes,
      this.Seller.Id.ToString());

    invoice.SetSellerContact($"{this.Seller.BuyerContact.FirstName} {this.Seller.BuyerContact.LastName}");

    foreach (LineItem lineItem in this.LineItems) {
      invoice.AddTradeLineItem(lineItem.Name, lineItem.Description, lineItem.QuantityCode, lineItem.Quantity, lineItem.GrossPrice, lineItem.GrossPrice, lineItem.Quantity);
    }

    invoice.LineTotalAmount = LineTotalAmount;
    invoice.ChargeTotalAmount = invoice.LineTotalAmount;
    invoice.AllowanceTotalAmount = Allowance;
    invoice.TaxBasisAmount = invoice.ChargeTotalAmount;
    invoice.TaxTotalAmount = TaxTotalAmount;
    invoice.GrandTotalAmount = GrandTotalAmount;

    MemoryStream ms = new MemoryStream();

    invoice.Save(ms, ZUGFeRDVersion.Version1, Profile.Basic);

    return ms.ToArray();
  }
}
```

### Creating the Invoice

The static method *Create* of the **Invoice** class is doing the actual merging work and embeds the generated XML into the created PDF. The method uses the MailMerge class to merge the data into the template and embeds the ZUGFeRD XML into a PDF/A-3b document.

```
public static class Invoice {
  public static byte[] Create(Order order) {

    TXTextControl.SaveSettings saveSettings = new TXTextControl.SaveSettings();

    var metaData = System.IO.File.ReadAllText("metadata.xml");

    // create a new embedded file
    var zugferdInvoice = new TXTextControl.EmbeddedFile(
      "ZUGFeRD-invoice.xml",
      order.ZugferdXML,
      metaData);

    zugferdInvoice.Description = "ZUGFeRD-invoice";
    zugferdInvoice.Relationship = "Alternative";
    zugferdInvoice.MIMEType = "application/xml";
    zugferdInvoice.LastModificationDate = DateTime.Now;

    // set the embedded files
    saveSettings.EmbeddedFiles = new TXTextControl.EmbeddedFile[] { zugferdInvoice };

    byte[] document;

    using (TXTextControl.ServerTextControl tx = new ServerTextControl()) {
      tx.Create();

      tx.Load("template.tx", StreamType.InternalUnicodeFormat);

      using (MailMerge mailMerge = new MailMerge()) {
        mailMerge.TextComponent = tx;
        mailMerge.MergeObject(order);
      }

      // export the PDF
      tx.Save(out document, TXTextControl.BinaryStreamType.AdobePDFA, saveSettings);

      return document;
    }
  }
}
```

### The Sample

The console application creates a new **Order** and calls the above *Invoice.Create* method and writes the created PDF document to a file.

```
using s2industries.ZUGFeRD;
using TXTextControl.DocumentServer.PDF.Zugferd;

Console.WriteLine("Creating ZUGFeRD Invoice...");

Order order = new Order() {
	Buyer = new ContractParty() {
		Address = "123 Street Dr.",
		CountryCodes = CountryCodes.US,
		BuyerContact = new ContractPartyContact() {
			FirstName = "Jack",
			LastName = "Sparrow"
		},
		City = "Charlotte",
		Id = 123,
		Name = "Company, LLC",
		PostalCode = "NC 28209"
	},
	Seller = new ContractParty() {
		Address = "333 Ave Dr.",
		CountryCodes = CountryCodes.US,
		BuyerContact = new ContractPartyContact() {
			FirstName = "Peter",
			LastName = "Jackson"
		},
		City = "Charlotte",
		Id = 123,
		Name = "Microogle, LLC",
		PostalCode = "NC 28210"
	},
	Id = 1,
	OrderDate = DateTime.Now,
	Allowance = 0,
	Vat = 6.5M,
	LineItems = new List<LineItem> {
					new LineItem() {
						Name = "Product A",
						Description = "Description A",
						Quantity = 5,
						QuantityCode = QuantityCodes.H87,
						GrossPrice = 432.00M
					},
					new LineItem() {
						Name = "Product B",
						Description = "Description B",
						Quantity = 2,
						QuantityCode = QuantityCodes.H87,
						GrossPrice = 5232.00M
					},
				}
};

File.WriteAllBytes("result.pdf", Invoice.Create(order));

Console.WriteLine("ZUGFeRD Invoice created successfully!");
```

After opening the PDF in Acrobat Reader, you can see the created visual representation and the embedded XML in the *Attachments* pane.

![Invoice PDF](https://s1-www.textcontrol.com/assets/dist/blog/2023/02/09/a/assets/pdf.webp "Invoice PDF")

When loading this document into a ZUGFeRD validator ([ZF/FX Validation](https://www.zugferd-community.net/de/dashboard/validation)), the results show a valid ZUGFeRD PDF.

![Invoice PDF](https://s1-www.textcontrol.com/assets/dist/blog/2023/02/09/a/assets/validation.webp "Invoice PDF")

You can download the sample from our GitHub repository to test this on your own.

---

## About Bjoern Meyer

As CEO, Bjoern is the visionary behind our strategic direction and business development, bridging the gap between our customers and engineering teams. His deep passion for coding and web technologies drives the creation of innovative products. If you're at a tech conference, be sure to stop by our booth - you'll most likely meet Bjoern in person. With an advanced graduate degree (Dipl. Inf.) in Computer Science, specializing in AI, from the University of Bremen, Bjoern brings significant expertise to his role. In his spare time, Bjoern enjoys running, paragliding, mountain biking, and playing the piano.

- [LinkedIn](https://www.linkedin.com/in/bjoernmeyer/)
- [X](https://x.com/txbjoern)
- [GitHub](https://github.com/bjoerntx)

---

## Related Posts

- [Why Structured E-Invoices Still Need Tamper Protection using C# and .NET](https://www.textcontrol.com/blog/2026/03/24/why-structured-e-invoices-still-need-tamper-protection-using-csharp-and-dotnet/llms.txt)
- [Visualize and Preview XRechnung, ZUGFeRD, and Factur-X Documents in .NET C#](https://www.textcontrol.com/blog/2025/01/02/visualize-and-preview-xrechnung-zugferd-and-factur-x-documents-in-net-csharp/llms.txt)
- [Creating ZUGFeRD 2.3 (XRechnung, Factur-X) Documents with .NET C#](https://www.textcontrol.com/blog/2025/01/02/creating-zugferd-2-3-xrechnung-factur-x-documents-with-net-c-sharp/llms.txt)
- [Using XRechnung / ZUGFeRD XML to Create PDF/A-3b Invoices with ASP.NET Core C#](https://www.textcontrol.com/blog/2024/09/23/using-xrechnung-zugferd-xml-to-create-pdf-a-3b-invoices-with-asp-net-core-c-sharp/llms.txt)
- [Generating a ZUGFeRD PDF with Existing XML Data using .NET C#](https://www.textcontrol.com/blog/2024/07/25/generating-a-zugferd-pdf-with-existing-xml-data-using-net-c-sharp/llms.txt)
- [Electronic Invoicing will Become Mandatory in Germany in 2025](https://www.textcontrol.com/blog/2024/04/10/electronic-invoicing-will-become-mandatory-in-germany-in-2025/llms.txt)
- [Creating Valid XRechnung / ZUGFeRD Invoices with ASP.NET Core C#](https://www.textcontrol.com/blog/2023/12/28/creating-valid-xrechnung-zugferd-invoices-with-asp-net-core-csharp/llms.txt)
- [Typical Use-Case: Invoice Generation with TX Text Control in C#](https://www.textcontrol.com/blog/2023/03/19/typical-usecase-invoice-generation-with-tx-text-control-in-csharp/llms.txt)
- [Creating Invoices from DOCX Templates in C# from Scratch](https://www.textcontrol.com/blog/2022/11/01/creating-invoices-from-docx-templates-in-csharp-from-scratch/llms.txt)
- [Invoice Deployment Strategies: Building an Invoice Portal](https://www.textcontrol.com/blog/2021/10/28/invoice-deployment-strategies/llms.txt)
- [Creating ZUGFeRD Compliant PDF Invoices in C#](https://www.textcontrol.com/blog/2021/02/03/creating-zugferd-compliant-pdf-invoices-in-csharp/llms.txt)
- [Extract ZUGFeRD/Factur-X XML Attachments from Adobe PDF/A-3b Documents](https://www.textcontrol.com/blog/2021/01/18/extract-zugferd-facturx-attachments-from-adobe-pdf-documents/llms.txt)
- [X19 Sneak Peek: Validating ZUGFeRD / Factur-X Invoices with TX Text Control](https://www.textcontrol.com/blog/2020/11/10/x19-sneak-peek-validating-zugferd-factur-x-invoices-with-tx-text-control/llms.txt)
- [PDF/A-3: The Better Container for Electronic Documents](https://www.textcontrol.com/blog/2020/07/23/pdfa-the-better-container-for-electronic-documents/llms.txt)
- [Text Control Announces PDF/A-3 Support: The Future of Electronic Invoices](https://www.textcontrol.com/blog/2020/07/21/text-control-announces-pdf-a-3-support/llms.txt)
