Buffered read from a large list
Your code is pretty well written and I can't see anything too much I'd change... 

(remainingCount &gt; maxToReadOnce) ? maxToReadOnce : remainingCount


might be clearer as 

Math.Min(maxToReadOnce, remainingCount) 


but other than that it all looks really sensible.



That said, by mixing the batching into the processing code both are harder to read. Batching (splitting/sharding/whatever you want to call it) comes up a lot - I have an extension method lying around for it:

public static IEnumerable&lt;IEnumerable&lt;T&gt;&gt; Batch&lt;T&gt;(this IEnumerable&lt;T&gt; enumerable, int batchSize)
{
    var c = 0;
    var batch = new List&lt;T&gt;();
    foreach (var item in enumerable)
    {
        batch.Add(item);
        if (++c % batchSize == 0)
        {
            yield return batch;
            batch = new List&lt;T&gt;();
        }
    }
    if (batch.Count != 0)
    {
        yield return batch;
    }
}


There are a whole bunch of variations on the above - feel free to make any changes... The ++c % batchSize == 0 has always bothered me a bit but I like the terseness of it.

With that extension method in place you can simplify your code to:

foreach (var batchOfEmails in emails.Batch(maxToReadOnce))
{
    Process(batchOfEmails);
}


(if you don't like var the type will be IEnumerable&lt;IEnumerable&lt;string&gt;&gt;)