public async Task <RunMergeTemplateProgress> RunMergeTemplateAsync(
            MergeTemplate mergeTemplate,
            Action <RunMergeTemplateProgress> progressReporter = null,
            CancellationToken cancellationToken = default(CancellationToken))
        {
            if (mergeTemplate == null)
            {
                throw new ArgumentNullException(nameof(mergeTemplate));
            }
            var emailMergeTemplate = mergeTemplate as EmailMergeTemplate;

            if (emailMergeTemplate == null)
            {
                throw new InvalidOperationException("Currently only mergeTemplates of type Email are supported.");
            }
            if (emailMergeTemplate.EmailTemplate == null)
            {
                throw new InvalidOperationException("MergeTemplate.EmailTemplate cannot ben null");
            }

            string range     = mergeTemplate.SheetName;
            var    dataRange = await _sheetsService.GetDataRangeAsync(
                mergeTemplate.SpreadSheetId, mergeTemplate.SheetName);

            if (mergeTemplate.HeaderRowNumber > 1)
            {
                // we'll define a custom range
                range = new A1Notation(mergeTemplate.SheetName,
                                       dataRange.StartColumn,
                                       mergeTemplate.HeaderRowNumber,
                                       dataRange.EndColumn,
                                       dataRange.EndRow).ToString();
            }

            if (!dataRange.EndRow.HasValue)
            {
                throw new InvalidOperationException($"Could not retrieve the number of rows in sheet {mergeTemplate.SheetName}");
            }

            var progress = new RunMergeTemplateProgress(
                dataRange.EndRow.Value - (dataRange.StartRow ?? 1));
            await _sheetsService.GetValuesAsDictionaryDataPump(mergeTemplate.SpreadSheetId,
                                                               range, async values =>
            {
                if (!ShouldProcess(mergeTemplate, values))
                {
                    progress.AddSkipped();
                    return;
                }

                try
                {
                    await ProcessMergeTemplateAsync(emailMergeTemplate.EmailTemplate, values);
                    progress.AddProcessed();
                }
                catch (Exception err)
                {
                    _logger.Error(err, "Error processing merge template");
                    progress.AddError();
                }
                finally
                {
                    progressReporter?.Invoke(progress);
                }
            });

            return(progress);
        }