After diving into OpenXML Friday in order to replace a Word 2007 .NET 1.1 Interop cluster of awfulness, I realized there wasn't a complete example from a dotx or docx Word file with Merge Fields, parsing the Merge Fields and then writing the merged file to a docx. So I'm writing this blog article to demonstrate a working example. I don't claim this to be a perfect example nor the "right" way to do it, but it works. If you have a "right" way to do it, please let me know by posting a comment below. To make life easier or if you simply want the code in front of you, I've zipped up the complete source code, sample Word 2013 docx and dotx file here. Use it as a basis for you app or whatever you feel like. I'd like to hear any success stories with it or if you have suggestions though. I am going to assume you have already downloaded the OpenXML SDK 2.0 and installed it. I should note I tested this on Visual Studio 2012 running Windows 8 and the Office 2013 Preview. Word Template with 2 Mail Merge Fields: [caption id="attachment_1524" align="aligncenter" width="300"] Word Template before Mail Merge[/caption] Word Document after Mail Merge: [caption id="attachment_1525" align="aligncenter" width="300"] Word Document after Mail Merge[/caption] So without further adieu lets dive into the code. You'll need to add a reference to DocumentFormat.OpenXml and WindowsBase. In your code you'll need to add these 3 lines to include the appropriate namespaces: [csharp] using DocumentFormat.OpenXml; using DocumentFormat.OpenXml.Packaging; using DocumentFormat.OpenXml.Wordprocessing; [/csharp] The bulk of the document generation code is in this function, I tried to document as much as possible on the "unique" OpenXML code [csharp] public RETURN_VAL GenerateDocument() { try { // Don't continue if the template file name is not found if (!File.Exists(_templateFileName)) { throw new Exception(message: "TemplateFileName (" + _templateFileName + ") does not exist"); } // If the file is a DOTX file convert it to docx if (_templateFileName.ToUpper().EndsWith("DOTX")) { RETURN_VAL resultValue = ConvertTemplate(); if (!resultValue.Value) { return resultValue; } } else { // Otherwise make a copy of the Word Document to the targetFileName File.Copy(_templateFileName, _targetFileName); } using (WordprocessingDocument docGenerated = WordprocessingDocument.Open(_targetFileName, true)) { docGenerated.ChangeDocumentType(WordprocessingDocumentType.Document); foreach (FieldCode field in docGenerated.MainDocumentPart.RootElement.Descendants<FieldCode>()) { var fieldNameStart = field.Text.LastIndexOf(FieldDelimeter, System.StringComparison.Ordinal); var fieldname = field.Text.Substring(fieldNameStart + FieldDelimeter.Length).Trim(); var fieldValue = GetMergeValue(FieldName: fieldname); // Go through all of the Run elements and replace the Text Elements Text Property foreach (Run run in docGenerated.MainDocumentPart.Document.Descendants<Run>()) { foreach (Text txtFromRun in run.Descendants<Text>().Where(a => a.Text == "«" + fieldname + "»")) { txtFromRun.Text = fieldValue; } } } // If the Document has settings remove them so the end user doesn't get prompted to use the data source DocumentSettingsPart settingsPart = docGenerated.MainDocumentPart.GetPartsOfType<DocumentSettingsPart>().First(); var oxeSettings = settingsPart.Settings.Where(a => a.LocalName == "mailMerge").FirstOrDefault(); if (oxeSettings != null) { settingsPart.Settings.RemoveChild(oxeSettings); settingsPart.Settings.Save(); } docGenerated.MainDocumentPart.Document.Save(); } return new RETURN_VAL { Value = true }; } catch (Exception ex) { return new RETURN_VAL { Value = false, Exception = "DocumentGeneration::generateDocument() - " + ex.ToString() }; } } [/csharp] In my scenario I had tons of dotx files and thus needed to convert them properly (renaming won't do for OpenXML merging) [csharp] private RETURN_VAL ConvertTemplate() { try { MemoryStream msFile = null; using (Stream sTemplate = File.Open(_templateFileName, FileMode.Open, FileAccess.Read)) { msFile = new MemoryStream((int)sTemplate.Length); sTemplate.CopyTo(msFile); msFile.Position = 0L; } using (WordprocessingDocument wpdFile = WordprocessingDocument.Open(msFile, true)) { wpdFile.ChangeDocumentType(DocumentFormat.OpenXml.WordprocessingDocumentType.Document); MainDocumentPart docPart = wpdFile.MainDocumentPart; docPart.AddExternalRelationship("", new Uri(_templateFileName, UriKind.RelativeOrAbsolute)); docPart.Document.Save(); } // Flush the MemoryStream to the file File.WriteAllBytes(_targetFileName, msFile.ToArray()); msFile.Close(); return new RETURN_VAL { Value = true }; } catch (Exception ex) { return new RETURN_VAL { Value = false, Exception = "DocumentGeneration::convertTemplate() - " + ex.ToString() }; } } [/csharp] In my actual application I have a pretty elaborate Mail Merge process pulling in from various sources (SQL Server and WCF Services), but to demonstrate a working application I wrote out a simple switch/case function. [csharp] private string GetMergeValue(string FieldName) { switch (FieldName) { case "CurrentDate": return DateTime.Now.ToShortDateString(); case "CPU_Count": return Environment.ProcessorCount.ToString(); default: throw new Exception(message: "FieldName (" + FieldName + ") was not found"); } } [/csharp]