Mail Merge - Letter

This demo uses the DevExpress Word Processing Document API to generate personalized letters based on the predefined template.

Select the employee (sender) and customer (recipient) from the drop-down menus. Use the Mail Merge and Save to… dropdown button to select the output format, perform mail merge, and download the result.

Sample document
MailMerge_Template.docx



using DevExpress.Office.Services;
using DevExpress.XtraRichEdit;
using DevExpress.XtraRichEdit.API.Native;

MemoryStream MailMergeDocument(Stream stream, Employee selectedEmployee, bool isPdfOutput, DocumentFormat targetFormat) {
    using var wordProcessor = new RichEditDocumentServer();

    var uriService = (IUriStreamService)wordProcessor.GetService(typeof(IUriStreamService));
    uriService.RegisterProvider(new WordMailMergeUriStreamProvider());

    wordProcessor.LoadDocument(stream);

    if(selectedEmployee == null)
        return null;

    var dataSource = new List<Employee>() { selectedEmployee };
    var options = wordProcessor.CreateMailMergeOptions();
    options.DataSource = dataSource;
    options.FirstRecordIndex = 0;
    options.LastRecordIndex = 0;

    using var tempWordProcessor = new RichEditDocumentServer();
    wordProcessor.MailMerge(options, tempWordProcessor.Document);

    var outputStream = new MemoryStream();
    if(isPdfOutput)
        tempWordProcessor.ExportToPdf(outputStream);
    else
        tempWordProcessor.SaveDocument(outputStream, targetFormat);

    outputStream.Position = 0;
    return outputStream;
}
public class WordMailMergeUriStreamProvider : IUriStreamProvider {
    const string Prefix = "dbimg://";
    Stream IUriStreamProvider.GetStream(string uri) {
        uri = uri.Trim();
        if(!uri.StartsWith(Prefix))
            return null;
        var strId = uri.Substring(Prefix.Length).Trim();
        int id;
        if(!int.TryParse(strId, out id))
            return null;
        var fileName = $"Documents/Photo{id}.jpeg";
        var bytes = new byte[0];
        using(FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read)) {
            var length = (int)fs.Length;
            bytes = new byte[length];
            fs.ReadExactly(bytes, 0, length);
        }
        return new MemoryStream(bytes);
    }
}